-
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(lhr): support null scores #5128
Conversation
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.
love this one. some small ideas but on the whole it's feelin great
return false; | ||
case 'numeric': | ||
case 'binary': | ||
return audit.score === 1; |
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.
did you want to handle the case of numeric audits pass if above PASS_THRESHOLD
?
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.
yeah good call 👍
case 'not-applicable': | ||
return true; | ||
case 'error': | ||
case 'informative': |
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.
why do all informative audits fail?
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.
so they show up as failing, it actually fits perfectly with our new scoreDisplayMode categories. if an informative audit has nothing to tell you it marks itself as not-applicable
;)
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.
aiight sg.
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.
should record this idea somewhere (to the lhr/lhr-lite description of these, maybe?)
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.
It's more an audit author concern since it's an immediate conclusion from the scoreDisplayMode that if an audit isn't not-applicable
it means it was applicable :)
maybe in the custom audit docs?
const perfCategory = sampleResults.reportCategories.find(cat => cat.id === 'performance'); | ||
const categoryDOM2 = renderer.render(perfCategory, sampleResults.reportGroups); | ||
assert.ok(!categoryDOM2.querySelector('.lh-audit-group--notapplicable')); | ||
const bestPracticeCat = sampleResults.reportCategories.find(cat => cat.id === 'best-practices'); |
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.
just curious, why switching to BP? ah because usertimings is now n/a.
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.
yeah bingo
@@ -275,12 +274,12 @@ class CategoryRenderer { | |||
group = auditsUngrouped; | |||
} | |||
|
|||
if (audit.result.scoreDisplayMode === 'not-applicable') { | |||
group.notApplicable.push(audit); | |||
} else if (audit.result.score === 1 && !audit.result.debugString) { |
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.
that logic on debugString seems rather incorrect tbh. glad it's gone.
@@ -17,7 +17,8 @@ class PerformanceCategoryRenderer extends CategoryRenderer { | |||
const element = this.dom.find('.lh-metric', tmpl); | |||
element.id = audit.result.name; | |||
// FIXME(paulirish): currently this sets a 'lh-metric--fail' class on error'd audits |
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.
can you also address this?
i'd prefer do not set a --fail class on these audits.
(I know i wrote it and put my own name. haha. So i'm asking super nicely with a cherry on top. :)
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.
haha sure
this.dom.find('.lh-gauge__percentage', tmpl).textContent = scoreOutOf100; | ||
const scoreOutOf100 = Math.round(numericScore * 100); | ||
this.dom.find('.lh-gauge__percentage', tmpl).textContent = category.score === null ? | ||
'?' : scoreOutOf100; |
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.
can you also apply a title attribute to that explains why its ?
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, text suggestion welcome right now "Errors occurred while auditing"
lighthouse-core/scoring.js
Outdated
*/ | ||
static arithmeticMean(items) { | ||
// If there is 1 null score, return a null average | ||
if (items.some(item => item.score === null && item.weight !== 0)) return null; |
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.
wdyt about an early filter in this method to get rid of the weight===0 items. then we don't need the check in here PLUS L32.
ndb, tho
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.
yeah sure sg 👍
@@ -73,7 +73,7 @@ class ReportGenerator { | |||
return category.audits.map(catAudit => { | |||
const audit = lhr.audits[catAudit.id]; | |||
return [category.name, audit.name, audit.description, audit.scoreDisplayMode, audit.score] | |||
.map(value => value.toString()) | |||
.map(value => value === null ? '0' : value.toString()) |
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 dont know what the CSV consumers want but i feel like getting 0 is a little weird. empty string seems slightly better.
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.
csv-validator requires that all values in the column are numbers (I tried 'null' as string originally), I have no preference here we can ditch csv-validator if we want to deviate?
cc @nourikhalass in case you have a preference for how null
scores show up in CSV
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 agree with @paulirish that 0 is a bit weird so empty string would be better. But as @patrickhulce says: csv-validator does not play along with that. Maybe its better to use -1 or omit the result entirely if the score is null.
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'll go with -1 for now since you're our primary CSV consumer 👍, PR welcome in the future if you think of a better canonical CSV-way to represent this :)
obvious other alternative is just stop validating the scores are numeric, how do you feel about that?
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 think that's fine since the validation library leaves a lot to be desired. Maybe in the future I'll look at a better / more robust way of validating the CSV . So I think you'll be OK if you don't validate that scores are numeric.
Also thanks for including me in the loop!
@brendankenny you wanna take a look? |
looks like manual expectations need updating |
lighthouse-core/audits/audit.js
Outdated
@@ -162,18 +163,26 @@ class Audit { | |||
|
|||
// If the audit was determined to not apply to the page, we'll reset it as informative only |
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.
this comment seems out of date now
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.
fixed
scoreDisplayMode = Audit.SCORING_MODES.NOT_APPLICABLE; | ||
result.rawValue = true; | ||
} | ||
|
||
if (result.error) { |
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.
is it possible to rework this code to be a flow through a set of mutually exclusive states so it's easy to see the possibilities?
e.g. score is null, if error
, it's always scoring mode error, else if it's been marked notApplicable
, it's mode notApplicable
, then manual
, and then only if it's binary or numeric is a score calculated?
description
seems like it might not fit the mold, but then maybe it's worth calling separately if it sits across the display modes differently than score
does
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.
this gets reworked immediately as part of #5132, fair to take up there?
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.
fair to take up there?
yeah, SG
@@ -228,14 +225,21 @@ class CategoryRenderer { | |||
wrapper.href = `#${category.id}`; | |||
wrapper.classList.add(`lh-gauge__wrapper--${Util.calculateRating(category.score)}`); | |||
|
|||
const numericScore = Number(category.score); |
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.
should call out casting null
to 0 here in a comment
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
@@ -259,11 +263,11 @@ class CategoryRenderer { | |||
notApplicable: !Array<!ReportRenderer.AuditJSON>}>} */ ({}); | |||
const auditsUngrouped = {passed: [], failed: [], notApplicable: []}; | |||
|
|||
nonManualAudits.forEach(audit => { | |||
nonManualAudits.forEach(auditRef => { |
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.
🎉
case 'not-applicable': | ||
return true; | ||
case 'error': | ||
case 'informative': |
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.
should record this idea somewhere (to the lhr/lhr-lite description of these, maybe?)
* @param {{score: (number|null), scoreDisplayMode: string}} audit | ||
* @return {boolean} | ||
*/ | ||
static didAuditPass(audit) { |
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.
maybe this shouldn't be considered if the audit "passed" (we even call out informative audits as not being able to be interpreted as pass/fail lol), but I can't think of a better word and this is the way we divide the sections in the report. Maybe add a comment that this is specifically for that distinction?
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.
yeah sure sg, I went back and forth on name, basically "shouldHideAudit" but not always
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.
actually, I could flip and do "shouldConsiderFailing" or something?
member.weight = 0; | ||
} | ||
|
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 think these members are auditRef
s now if you want to do a drive by in this function :)
whoops yeah fixed them on the wrong branch 😆 |
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.
LGTM!
followup to #5105, add support for null scores and forces all errors/informative/manual/not-applicable to be null
when category errors, the gauge shows '?'
I'll try to find a screenshot:)