-
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
refactor(StartUrl): switch from error to debugString object #2549
Changes from 9 commits
fbd724e
d3c8dfd
f98d4b9
6589cdd
1cf9b18
369058d
6cefcd6
5c9b84b
4a0e7d4
c552cab
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 |
---|---|---|
|
@@ -43,7 +43,8 @@ class WebappInstallBanner extends MultiCheckAudit { | |
}; | ||
} | ||
|
||
static assessManifest(manifestValues, failures) { | ||
static assessManifest(artifacts, result) { | ||
const {manifestValues, failures} = result; | ||
if (manifestValues.isParseFailure) { | ||
failures.push(manifestValues.parseFailureReason); | ||
return; | ||
|
@@ -66,32 +67,37 @@ class WebappInstallBanner extends MultiCheckAudit { | |
} | ||
|
||
|
||
static assessServiceWorker(artifacts, failures) { | ||
static assessServiceWorker(artifacts, result) { | ||
const hasServiceWorker = SWAudit.audit(artifacts).rawValue; | ||
if (!hasServiceWorker) { | ||
failures.push('Site does not register a Service Worker'); | ||
result.failures.push('Site does not register a Service Worker'); | ||
} | ||
} | ||
|
||
static assessOfflineStartUrl(artifacts, failures) { | ||
const hasOfflineStartUrl = artifacts.StartUrl === 200; | ||
static assessOfflineStartUrl(artifacts, result) { | ||
const hasOfflineStartUrl = artifacts.StartUrl.statusCode === 200; | ||
|
||
if (!hasOfflineStartUrl) { | ||
failures.push('Manifest start_url is not cached by a Service Worker'); | ||
result.failures.push('Manifest start_url is not cached by a Service Worker'); | ||
|
||
if (artifacts.StartUrl.debugString) { | ||
result.failures.push(artifacts.StartUrl.debugString); | ||
} | ||
} else if (artifacts.StartUrl.debugString) { | ||
result.debugString = artifacts.StartUrl.debugString; | ||
} | ||
} | ||
|
||
static audit_(artifacts) { | ||
const failures = []; | ||
|
||
return artifacts.requestManifestValues(artifacts.Manifest).then(manifestValues => { | ||
WebappInstallBanner.assessManifest(manifestValues, failures); | ||
WebappInstallBanner.assessServiceWorker(artifacts, failures); | ||
WebappInstallBanner.assessOfflineStartUrl(artifacts, failures); | ||
|
||
return { | ||
failures, | ||
manifestValues | ||
}; | ||
const result = {failures, manifestValues}; | ||
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. if 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. done |
||
WebappInstallBanner.assessManifest(artifacts, result); | ||
WebappInstallBanner.assessServiceWorker(artifacts, result); | ||
WebappInstallBanner.assessOfflineStartUrl(artifacts, result); | ||
|
||
return result; | ||
}); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -265,25 +265,18 @@ class Driver { | |
} | ||
|
||
getAppManifest() { | ||
return new Promise((resolve, reject) => { | ||
this.sendCommand('Page.getAppManifest') | ||
.then(response => { | ||
// We're not reading `response.errors` however it may contain critical and noncritical | ||
// errors from Blink's manifest parser: | ||
// https://chromedevtools.github.io/debugger-protocol-viewer/tot/Page/#type-AppManifestError | ||
if (!response.data) { | ||
if (response.url) { | ||
return reject(new Error(`Unable to retrieve manifest at ${response.url}.`)); | ||
} | ||
|
||
// If both the data and the url are empty strings, the page had no manifest. | ||
return reject('No web app manifest found.'); | ||
} | ||
return this.sendCommand('Page.getAppManifest') | ||
.then(response => { | ||
// We're not reading `response.errors` however it may contain critical and noncritical | ||
// errors from Blink's manifest parser: | ||
// https://chromedevtools.github.io/debugger-protocol-viewer/tot/Page/#type-AppManifestError | ||
if (!response.data) { | ||
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. why drop the 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. IMO, anything that's not a bug should not say 'GathererError: blah', if the manifest 404s that's not a bug so it shouldn't be an error, at best we can give them the slightly different debug strings, is that what you're pushing back against? 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. Saying "No web app manifest found on page" is definitely wrong in that case, so a better error string is needed. But I'm not sure I agree about Gatherer errors. I have no problem with a method fetching a manifest throwing on a manifest URL that doesn't exist. But I assume the issue is us conflating Lighthouse bugs with exceptional states? We may need to get back into that conversation to get the functionality we need. We don't want to slide back into -1 land where every audit has to handle all possible gatherer error states, but agreed we probably need a better separation between the classes of errors. 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've got no problem with this throwing either just the overall pass throwing instead of returning debugString. There should be some distinguishing from a user's perspective between a bug they have no control over and something they need to take action on. 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 re:
I'd don't actually agree that "Unable to retrieve manifest" is better than "No web app manifest found on page", as a user receiving the former I may believe that it's LH problem not being able to retrieve it and there's nothing for me to do whereas the latter gets me to check my manifest. There's probably room for improvement on both, but calling it "definitely wrong" seems overly critical. It's not wrong, there was no usable manifest found. 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. maybe we need to start laying out the failure states for an audit ahead of time so we can decide on them once (in theory) and then it's obvious when they're implemented or not :) If there's no Agreed "Unable to retrieve manifest" is a bad error string for that and we should be as specific as possible to help with those situations. Also totally on board with exploring non-exception error returns, expected errors, etc after this so we can separate the two (or more?) clear classes of errors we're dealing with here. 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.
One downside of the current 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. (the devtools Application panel suffers from the same problem, only showing "Errors and warnings: 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.
Yeah feels like it should return something similar to an artifact |
||
// If the data is empty, the page had no manifest. | ||
return null; | ||
} | ||
|
||
resolve(response); | ||
}) | ||
.catch(err => reject(err)); | ||
}); | ||
return response; | ||
}); | ||
} | ||
|
||
getSecurityState() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,34 +49,54 @@ class StartUrl extends Gatherer { | |
pass(options) { | ||
return options.driver.getAppManifest() | ||
.then(response => { | ||
return manifestParser(response.data, response.url, options.url); | ||
return response && manifestParser(response.data, response.url, options.url); | ||
}) | ||
.then(manifest => { | ||
if (!manifest.value.start_url || !manifest.value.start_url.raw) { | ||
return Promise.reject(new Error(`No web app manifest found on page ${options.url}`)); | ||
if (!manifest || !manifest.value) { | ||
const detailedMsg = manifest && manifest.debugString; | ||
this.debugString = detailedMsg ? | ||
`Error fetching web app manifest: ${detailedMsg}` : | ||
`No usable web app manifest found on page ${options.url}`; | ||
return; | ||
} | ||
|
||
if (manifest.value.start_url.debugString) { | ||
return Promise.reject(new Error(manifest.value.start_url.debugString)); | ||
// Even if the start URL had an error, the browser will still supply a fallback URL. | ||
// Therefore, we only set the debugString here and continue with the fetch. | ||
this.debugString = manifest.value.start_url.debugString; | ||
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. should this be a state with a 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. hm, why? there's nothing to fetch if the start_url is bad 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.
if there's a parseable JSON file there's always a good 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. oh I see now, faulty start_urls are always ignored debugString seems rather useless then there will always be a usable start_url... 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.
it is useful for debugging to see if your manifest isn't acting like you think it should...e.g. you have one start_url in mind and it's defaulting to another. That might be really hard to track down (or even notice that it's happening) otherwise. I guess that makes me fall on the side of the current code and just show the error :) Lighthouse can be stricter than the spec in that case 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 guess this gets into the division of labor between DevTools and LH. LH shouldn't be your debugger IMO outside of general messages to get you on the right track/where to start looking. If everything is working from the PWA perspective (and document url was the right start url), do you really care about being flagged that you don't have a valid start url? Either way, I added back the debug string to still do the check so if it passes it should pass with the debugString 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 think that's a good solution for now and the devtools/LH discussion is a good one to revisit now that Audits 2.0 is a real thing. Pavel and Paul also love drawing diagrams about that sort of division so I'm sure they'd be happy to get in on it :) 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.
haha :) 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. maybe a comment here as a reminder that even with a 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. done |
||
} | ||
|
||
this.startUrl = manifest.value.start_url.value; | ||
}).then(_ => this.executeFetchRequest(options.driver, this.startUrl)); | ||
return this.executeFetchRequest(options.driver, this.startUrl); | ||
}); | ||
} | ||
|
||
afterPass(options, tracingData) { | ||
if (!this.startUrl) { | ||
return Promise.reject(new Error('No start_url found inside the manifest')); | ||
} | ||
|
||
const networkRecords = tracingData.networkRecords; | ||
const navigationRecord = networkRecords.filter(record => { | ||
return URL.equalWithExcludedFragments(record._url, this.startUrl) && | ||
record._fetchedViaServiceWorker; | ||
}).pop(); // Take the last record that matches. | ||
|
||
return options.driver.goOnline(options) | ||
.then(_ => navigationRecord ? navigationRecord.statusCode : -1); | ||
.then(_ => { | ||
if (!this.startUrl) { | ||
return { | ||
statusCode: -1, | ||
debugString: this.debugString || 'No start URL to fetch', | ||
}; | ||
} else if (!navigationRecord) { | ||
return { | ||
statusCode: -1, | ||
debugString: this.debugString || 'Did not fetch start URL from service worker', | ||
}; | ||
} else { | ||
return { | ||
statusCode: navigationRecord.statusCode, | ||
debugString: this.debugString, | ||
}; | ||
} | ||
}); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,7 +103,7 @@ URL.elideDataURI = function elideDataURI(url) { | |
// Why? Special handling was added by Chrome team to allow a pushState transition between chrome:// pages. | ||
// As a result, the network URL (chrome://chrome/settings/) doesn't match the final document URL (chrome://settings/). | ||
function rewriteChromeInternalUrl(url) { | ||
if (!url.startsWith('chrome://')) return url; | ||
if (!url || !url.startsWith('chrome://')) return url; | ||
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. what new path needs this? 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. this was a drive-by fix of something I encountered on another branch, can't remember what site now though it was over a month ago :P 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. but to answer your question the 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.
ha, I had forgotten we had done that. I guess that's fine vs moving the |
||
return url.replace(/^chrome:\/\/chrome\//, 'chrome://'); | ||
} | ||
|
||
|
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.
weird, I left this comment before (and it was in the email), but it was eaten in the web interface:
so here (for this idea) it would
result.warnings.push(artifacts.StartUrl.debugString);
whether or not ithasOfflineStartUrl
, and thenMultiCheckAudit
would handle appendingresult.warnings.join(', ')
to thedebugString
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.
done