diff --git a/docs/architecture.md b/docs/architecture.md index 7cba6909f21a..49ce30f22cc3 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -9,9 +9,9 @@ _Some incomplete notes_ * **Driver** - Interfaces with [Chrome Debugging Protocol](https://developer.chrome.com/devtools/docs/debugger-protocol) ([API viewer](https://chromedevtools.github.io/debugger-protocol-viewer/)) * **Gatherers** - Uses Driver to collect information about the page. Minimal post-processing. * **Artifacts** - output of a gatherer -* **Audit** - Tests for a single feature/optimization/metric. Using the Artifacts as input, an audit evaluates a test and resolves to a score which may be pass/fail/numeric. Formatting note: The meta description may contain markdown links and meta title may contain markdown code. +* **Audit** - Tests for a single feature/optimization/metric. Using the Artifacts as input, an audit evaluates a test and resolves to a numeric score. See [Understanding Results](./understanding-results.md) for details of the results object. * **Computed Artifacts** - Generated on-demand from artifacts, these add additional meaning, and are often shared amongst multiple audits. - + ### Audit/Report terminology * **Category** - Roll-up collection of audits and audit groups into a user-facing section of the report (eg. `Best Practices`). Applies weighting and overall scoring to the section. Examples: PWA, Accessibility, Best Practices. * **Audit description** - Short user-visible title for the successful audit. eg. “All image elements have `[alt]` attributes.” diff --git a/docs/puppeteer.md b/docs/puppeteer.md index d1a145baa33c..5e880e072671 100644 --- a/docs/puppeteer.md +++ b/docs/puppeteer.md @@ -30,7 +30,7 @@ browser.on('targetchanged', async target => { style.appendChild(document.createTextNode(content)); document.head.appendChild(style); } - + const css = '* {color: red}'; if (page && page.url() === url) { @@ -51,7 +51,7 @@ const lhr = await lighthouse(url, { logLevel: 'info', }); -console.log(`Lighthouse score: ${lhr.score}`); +console.log(`Lighthouse scores: ${lhr.reportCategories.map(c => c.score).join(', ')}`); await browser.close(); })(); @@ -90,7 +90,7 @@ const browser = await puppeteer.connect({browserWSEndpoint: webSocketDebuggerUrl // Run Lighthouse. const lhr = await lighthouse(URL, opts, null); -console.log(`Lighthouse score: ${lhr.score}`); +console.log(`Lighthouse scores: ${lhr.reportCategories.map(c => c.score).join(', ')}`); await browser.disconnect(); await chrome.kill(); diff --git a/docs/scoring.md b/docs/scoring.md index 6200847bccbd..b02b0fe009d2 100644 --- a/docs/scoring.md +++ b/docs/scoring.md @@ -1,5 +1,5 @@ # Goal -The goal of this document is to explain how scoring works in Lighthouse and what to do to improve your Lighthouse scores across the four sections of the report. +The goal of this document is to explain how scoring works in Lighthouse and what to do to improve your Lighthouse scores across the four sections of the report. Note 1: if you want a **nice spreadsheet** version of this doc to understand weighting and scoring, check out the [scoring spreadsheet](https://docs.google.com/spreadsheets/d/1dXH-bXX3gxqqpD1f7rp6ImSOhobsT1gn_GQ2fGZp8UU/edit?ts=59fb61d2#gid=0) @@ -9,22 +9,22 @@ Note 1: if you want a **nice spreadsheet** version of this doc to understand wei Note 2: if you receive a **score of 0** in any Lighthouse category, that usually indicates an error on our part. Please file an [issue](https://github.com/GoogleChrome/lighthouse/issues) so our team can look into it. # Performance - + ### What performance metrics does Lighthouse measure? -Lighthouse measures the following performance metrics: +Lighthouse measures the following performance metrics: -- [First meaningful paint](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint): first meaningful paint is defined as when the browser first puts any “meaningful” element/set of “meaningful” elements on the screen. What is meaningful is determined from a series of heuristics. -- [First interactive](https://developers.google.com/web/tools/lighthouse/audits/first-interactive): first interactive is defined as the first point at which the page could respond quickly to input. It doesn't consider any point in time before first meaningful paint. The way this is implemented is primarily based on heuristics. +- [First meaningful paint](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint): first meaningful paint is defined as when the browser first puts any “meaningful” element/set of “meaningful” elements on the screen. What is meaningful is determined from a series of heuristics. +- [First interactive](https://developers.google.com/web/tools/lighthouse/audits/first-interactive): first interactive is defined as the first point at which the page could respond quickly to input. It doesn't consider any point in time before first meaningful paint. The way this is implemented is primarily based on heuristics. *Note: this metric is currently in beta, which means that the underlying definition of this metric is in progress.* -- [Consistently interactive](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive): defined as the first point at which everything is loaded such that the page will quickly respond to any user input throughout the page. +- [Consistently interactive](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive): defined as the first point at which everything is loaded such that the page will quickly respond to any user input throughout the page. *Note: this metric is currently in beta, which means that the underlying definition of this metric is in progress.* -- [Perceptual Speed Index (pSI)](https://developers.google.com/web/tools/lighthouse/audits/speed-index): pSI measures how many pixels are painted at each given time interval on the viewport. The earlier the pixels are painted, the better you score on metric since we want an experience where most of the content is shown on the screen during the first few moments of initiating the page load. Loading more content earlier makes your end user feel like the website is loading quickly, which contributes to a positive user experience. Therefore, the lower the pSI score, the better. +- [Perceptual Speed Index (pSI)](https://developers.google.com/web/tools/lighthouse/audits/speed-index): pSI measures how many pixels are painted at each given time interval on the viewport. The earlier the pixels are painted, the better you score on metric since we want an experience where most of the content is shown on the screen during the first few moments of initiating the page load. Loading more content earlier makes your end user feel like the website is loading quickly, which contributes to a positive user experience. Therefore, the lower the pSI score, the better. - [Estimated Input Latency](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency): this audit measures how fast your app is in responding to user input. Our benchmark is that the estimated input latency should be under 50 ms (see documentation [here](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency) as to why). *Some **variability** when running on real-world sites is to be expected as sites load different ads, scripts, and network conditions vary for each visit. Note that Lighthouse can especially experience inconsistent behaviors when it runs in the presence of anti-virus scanners, other extensions or programs that interfere with page load, and inconsistent ad behavior. Please try to run without anti-virus scanners or other extensions/programs to get the cleanest results, or alternatively, run Lighthouse on WebPageTest for the most consistent results [here](https://www.webpagetest.org/easy.php).* ### How are the scores weighted? -Lighthouse returns a performance score from 0-100. A score of 0 usually indicates an error with performance measurement (so file an issue in the Lighthouse repo if further debugging is needed), and 100 is the best possible ideal score (really hard to get). Usually, any score above a 90 gets you in the top ~5% of performant websites. +Lighthouse returns a performance score from 0-100 (technically returned as 0-1, but you can do the math ;). A score of 0 usually indicates an error with performance measurement (so file an issue in the Lighthouse repo if further debugging is needed), and 100 is the best possible ideal score (really hard to get). Usually, any score above a 90 gets you in the top ~5% of performant websites. The performance score is determined from the **performance metrics only**. The Opportunities/Diagnostics sections do not directly contribute to the performance score. @@ -36,30 +36,30 @@ The metric results are not weighted equally. Currently the weights are: * 1X - perceptual speed index * 1X - estimated input latency -These weights were determined based on heuristics, and the Lighthouse team is working on formalizing this approach through more field data. +These weights are heuristics, and the Lighthouse team is working on formalizing the weighting system through more field data. ### How do performance metrics get scored? Once Lighthouse is done gathering the raw performance metrics for your website (metrics reported in miliseconds), it converts them into a score by mapping the raw performance number to a number between 0-100 by looking where your raw performance metric falls on the Lighthouse scoring distribution. The Lighthouse scoring distribution is a log normal distribution that is derived from the performance metrics of real website performance data (see sample distribution [here](https://www.desmos.com/calculator/zrjq6v1ihi)). -Once we finish computing the percentile equivalent of your raw performance score, we take the weighted average of all the performance metrics (per the weighting above, with 5x weight given to first meaningful weight, first interactive, and consistently interactive). Finally, we apply a coloring to the score (green, orange, and red) depending on what "bucket" your score falls in. Roughly, this maps to: -- Red (poor score): 0-44. -- Orange (average): 45-74 -- Green (good): 75-100. +Once we finish computing the percentile equivalent of your raw performance score, we take the weighted average of all the performance metrics (per the weighting above, with 5x weight given to first meaningful weight, first interactive, and consistently interactive). Finally, we apply a coloring to the score (green, orange, and red) depending on what "bucket" your score falls in. Roughly, this maps to: +- Red (poor score): 0-44. +- Orange (average): 45-74 +- Green (good): 75-100. ### What can developers do to improve their performance score? *Note: we've built [a little calculator](https://docs.google.com/spreadsheets/d/1dXH-bXX3gxqqpD1f7rp6ImSOhobsT1gn_GQ2fGZp8UU/edit?ts=59fb61d2#gid=283330180) that can help you understand what thresholds you should be aiming for achieving a certain Lighthouse performance score. * -Lighthouse has a whole section in the report on improving your performance score under the “Opportunities” section. There are detailed suggestions and documentation that explains the different suggestions and how to implement them. Additionally, the diagnostics section lists additional guidance that developers can explore to further experiment and tweak with their performance. +Lighthouse has a whole section in the report on improving your performance score under the “Opportunities” section. There are detailed suggestions and documentation that explains the different suggestions and how to implement them. Additionally, the diagnostics section lists additional guidance that developers can explore to further experiment and tweak with their performance. # PWA -### How is the PWA score calculated? -The PWA score is calculated based on the [Baseline PWA checklist](https://developers.google.com/web/progressive-web-apps/checklist#baseline), which lists 14 requirements. Lighthouse tests for 11 out of the 14 requirements automatically, with the other 3 being manual checks. Each of the 11 audits for the PWA section of the report is weighted equally, so implementing any of the audits correctly will increase your overall score by ~9 points. +### How is the PWA score calculated? +The PWA score is calculated based on the [Baseline PWA checklist](https://developers.google.com/web/progressive-web-apps/checklist#baseline), which lists 14 requirements. Lighthouse tests for 11 out of the 14 requirements automatically, with the other 3 being manual checks. Each of the 11 audits for the PWA section of the report is weighted equally, so implementing any of the audits correctly will increase your overall score by ~9 points. # Accessibility ### How is the accessibility score calculated? -The accessibility score is a weighted average of all the different audits (the weights for each audit can be found in [the scoring spreadsheet](https://docs.google.com/spreadsheets/d/1dXH-bXX3gxqqpD1f7rp6ImSOhobsT1gn_GQ2fGZp8UU/edit?ts=59fb61d2#gid=0)). Each audit is a pass/fail (meaning there is no room for partial points for getting an audit half-right). For example, that means if half your buttons have screenreader friendly names, and half don't, you don't get "half" of the weighted average-you get a 0 because it needs to be implemented *throughout* the page. +The accessibility score is a weighted average of all the different audits (the weights for each audit can be found in [the scoring spreadsheet](https://docs.google.com/spreadsheets/d/1dXH-bXX3gxqqpD1f7rp6ImSOhobsT1gn_GQ2fGZp8UU/edit?ts=59fb61d2#gid=0)). Each audit is a pass/fail (meaning there is no room for partial points for getting an audit half-right). For example, that means if half your buttons have screenreader friendly names, and half don't, you don't get "half" of the weighted average-you get a 0 because it needs to be implemented *throughout* the page. # Best Practices -### How is the Best Practices score calculated? -Each audit in the Best Practices section is equally weighted. Therefore, implementing each audit correctly will increase your overall score by ~6 points. +### How is the Best Practices score calculated? +Each audit in the Best Practices section is equally weighted. Therefore, implementing each audit correctly will increase your overall score by ~6 points. diff --git a/docs/understanding-results.md b/docs/understanding-results.md index 0e8dc1ba82dc..b867aa82cbb4 100644 --- a/docs/understanding-results.md +++ b/docs/understanding-results.md @@ -15,7 +15,6 @@ The top-level Lighthouse Results object (LHR) is what the lighthouse node module | userAgent | The user agent string of the version of Chrome that was used by Lighthouse. | | initialUrl | The URL that was supplied to Lighthouse and initially navigated to. | | url | The URL that Lighthouse ended up auditing after redirects were followed. | -| score | The overall score `0-100`, a weighted average of all category scores. *NOTE: Only the PWA category has a weight by default* | | [audits](#audits) | An object containing the results of the audits. | | [runtimeConfig](#runtime-config) | An object containing information about the configuration used by Lighthouse. | | [timing](#timing) | An object containing information about how long Lighthouse spent auditing. | @@ -50,14 +49,14 @@ An object containing the results of the audits, keyed by their name. | Name | Type | Description | | -- | -- | -- | | name | `string` | The string identifier of the audit in kebab case. | -| description | `string` | The brief description of the audit. The text can change depending on if the audit passed or failed. | +| description | `string` | The brief description of the audit. The text can change depending on if the audit passed or failed. It may contain markdown code. | | helpText | `string` | A more detailed description that describes why the audit is important and links to Lighthouse documentation on the audit, markdown links supported. | | debugString | string|undefined | A string indicating some additional information to the user explaining an unusual circumstance or reason for failure. | | error | `boolean` | Set to true if there was an an exception thrown within the audit. The error message will be in `debugString`. | rawValue | boolean|number | The unscored value determined by the audit. Typically this will match the score if there's no additional information to impart. For performance audits, this value is typically a number indicating the metric value. | | displayValue | `string` | The string to display in the report alongside audit results. If empty, nothing additional is shown. This is typically used to explain additional information such as the number and nature of failing items. | -| score | boolean|number | The scored value determined by the audit as either boolean or a number `0-100`. If the audit is a boolean, the implication is `score ? 100 : 0`. | -| scoringMode | "binary"|"numeric" | A string identifying how granular the score is meant to be indicating, i.e. is the audit pass/fail or are there shades of gray 0-100. *NOTE: This does not necessarily mean `typeof audit.score === audit.scoringMode`, an audit can have a score of 40 with a scoringMode of `"binary"` meant to indicate display should be failure.* | +| score | number | The scored value determined by the audit as a number `0-1`, representing displayed scores of 0-100. | +| scoreDisplayMode | "binary"|"numeric" | A string identifying how the score should be interpreted i.e. is the audit pass/fail (score of 1 or 0), or are there shades of gray (scores between 0-1 inclusive). | | details | `Object` | Extra information found by the audit necessary for display. The structure of this object varies from audit to audit. The structure of this object is somewhat stable between minor version bumps as this object is used to render the HTML report. | extendedInfo | `Object` | Extra information found by the audit. The structure of this object varies from audit to audit and is generally for programmatic consumption and debugging, though there is typically overlap with `details`. *WARNING: The structure of this object is not stable and cannot be trusted to follow semver* | | manual | `boolean` | Indicator used for display that the audit does not have results and is a placeholder for the user to conduct manual testing. | @@ -74,10 +73,10 @@ An object containing the results of the audits, keyed by their name. "description": "Uses HTTPS", "failureDescription": "Does not use HTTPS", "helpText": "HTTPS is the best. [Learn more](https://learn-more)", - "score": false, + "score": 0, "rawValue": false, "displayValue": "2 insecure requests found", - "scoringMode": "binary", + "scoreDisplayMode": "binary", "details": { "type": "list", "header": { @@ -185,7 +184,6 @@ An array containing the different categories, their scores, and the results of t | Name | Type | Description | | -- | -- | -- | | id | `string` | The string identifier of the category. | -| score | `number` | The numeric score `0-100` of the audit. Audits with a boolean score result are converted with `score ? 100 : 0`. | | weight | `number` | The weight of the audit's score in the overall category score. | | result | `Object` | The actual audit result, a copy of the audit object found in [audits](#audits). *NOTE: this property will likely be removed in upcoming releases; use the `id` property to lookup the result in the `audits` property.* | @@ -205,7 +203,7 @@ An array containing the different categories, their scores, and the results of t "weight": 1, "result": { "name": "is-on-https", - "score": false, + "score": 0, ... } } diff --git a/lighthouse-cli/test/smokehouse/a11y/expectations.js b/lighthouse-cli/test/smokehouse/a11y/expectations.js index 81ecde776b57..9f53b79dc1bc 100644 --- a/lighthouse-cli/test/smokehouse/a11y/expectations.js +++ b/lighthouse-cli/test/smokehouse/a11y/expectations.js @@ -14,7 +14,7 @@ module.exports = [ url: 'http://localhost:10200/a11y/a11y_tester.html', audits: { 'accesskeys': { - score: false, + score: 0, details: { items: { length: 1, @@ -22,7 +22,7 @@ module.exports = [ }, }, 'aria-allowed-attr': { - score: false, + score: 0, details: { items: { length: 1, @@ -30,7 +30,7 @@ module.exports = [ }, }, 'aria-required-children': { - score: false, + score: 0, details: { items: { length: 1, @@ -38,7 +38,7 @@ module.exports = [ }, }, 'aria-required-parent': { - score: false, + score: 0, details: { items: { length: 1, @@ -46,7 +46,7 @@ module.exports = [ }, }, 'aria-roles': { - score: false, + score: 0, details: { items: { length: 1, @@ -54,7 +54,7 @@ module.exports = [ }, }, 'aria-valid-attr-value': { - score: false, + score: 0, details: { items: { length: 1, @@ -62,7 +62,7 @@ module.exports = [ }, }, 'aria-valid-attr': { - score: false, + score: 0, details: { items: { length: 1, @@ -70,7 +70,7 @@ module.exports = [ }, }, 'button-name': { - score: false, + score: 0, details: { items: { length: 1, @@ -78,7 +78,7 @@ module.exports = [ }, }, 'bypass': { - score: false, + score: 0, details: { items: { length: 1, @@ -86,7 +86,7 @@ module.exports = [ }, }, 'color-contrast': { - score: false, + score: 0, details: { items: { length: 1, @@ -94,7 +94,7 @@ module.exports = [ }, }, 'definition-list': { - score: false, + score: 0, details: { items: { length: 1, @@ -102,7 +102,7 @@ module.exports = [ }, }, 'dlitem': { - score: false, + score: 0, details: { items: { length: 1, @@ -110,7 +110,7 @@ module.exports = [ }, }, 'document-title': { - score: false, + score: 0, details: { items: { length: 1, @@ -118,7 +118,7 @@ module.exports = [ }, }, 'duplicate-id': { - score: false, + score: 0, details: { items: { length: 1, @@ -126,7 +126,7 @@ module.exports = [ }, }, 'frame-title': { - score: false, + score: 0, details: { items: { length: 1, @@ -134,7 +134,7 @@ module.exports = [ }, }, 'html-has-lang': { - score: false, + score: 0, details: { items: { length: 1, @@ -142,7 +142,7 @@ module.exports = [ }, }, 'image-alt': { - score: false, + score: 0, details: { items: { length: 1, @@ -150,7 +150,7 @@ module.exports = [ }, }, 'input-image-alt': { - score: false, + score: 0, details: { items: { length: 1, @@ -158,7 +158,7 @@ module.exports = [ }, }, 'label': { - score: false, + score: 0, details: { items: { length: 1, @@ -166,7 +166,7 @@ module.exports = [ }, }, 'layout-table': { - score: false, + score: 0, details: { items: { length: 1, @@ -174,7 +174,7 @@ module.exports = [ }, }, 'link-name': { - score: false, + score: 0, details: { items: { length: 1, @@ -182,7 +182,7 @@ module.exports = [ }, }, 'list': { - score: false, + score: 0, details: { items: { length: 1, @@ -190,7 +190,7 @@ module.exports = [ }, }, 'listitem': { - score: false, + score: 0, details: { items: { length: 1, @@ -198,7 +198,7 @@ module.exports = [ }, }, 'meta-viewport': { - score: false, + score: 0, details: { items: { length: 1, @@ -206,7 +206,7 @@ module.exports = [ }, }, 'object-alt': { - score: false, + score: 0, details: { items: { length: 1, @@ -214,7 +214,7 @@ module.exports = [ }, }, 'tabindex': { - score: false, + score: 0, details: { items: { length: 1, @@ -222,7 +222,7 @@ module.exports = [ }, }, 'td-headers-attr': { - score: false, + score: 0, details: { items: { length: 1, @@ -230,7 +230,7 @@ module.exports = [ }, }, 'valid-lang': { - score: false, + score: 0, details: { items: { length: 1, diff --git a/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js b/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js index 883cc990bda4..cf078d287ce2 100644 --- a/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js +++ b/lighthouse-cli/test/smokehouse/byte-efficiency/expectations.js @@ -27,7 +27,7 @@ module.exports = [ }, }, 'unminified-javascript': { - score: '<100', + score: '<1', extendedInfo: { value: { wastedKb: 45, @@ -49,7 +49,7 @@ module.exports = [ }, }, 'unused-javascript': { - score: '<100', + score: '<1', extendedInfo: { value: { wastedKb: '>=25', @@ -61,7 +61,7 @@ module.exports = [ }, }, 'offscreen-images': { - score: '<100', // big enough savings to interfere with download of script.js + score: '<1', // big enough savings to interfere with download of script.js extendedInfo: { value: { results: [ @@ -79,7 +79,7 @@ module.exports = [ }, }, 'uses-webp-images': { - score: '<100', // big enough savings to interfere with download of script.js + score: '<1', // big enough savings to interfere with download of script.js extendedInfo: { value: { wastedKb: '>60', diff --git a/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js b/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js index edfc18cc4635..69c346a7e828 100644 --- a/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js +++ b/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js @@ -14,7 +14,7 @@ module.exports = [ url: 'http://localhost:10200/dobetterweb/dbw_tester.html', audits: { 'errors-in-console': { - score: false, + score: 0, rawValue: '>3', details: { items: { @@ -23,7 +23,7 @@ module.exports = [ }, }, 'is-on-https': { - score: false, + score: 0, extendedInfo: { value: { length: 1, @@ -31,7 +31,7 @@ module.exports = [ }, }, 'uses-http2': { - score: false, + score: 0, extendedInfo: { value: { results: { @@ -46,7 +46,7 @@ module.exports = [ }, }, 'external-anchors-use-rel-noopener': { - score: false, + score: 0, debugString: 'Lighthouse was unable to determine the destination of some anchor tags. ' + 'If they are not used as hyperlinks, consider removing the _blank target.', extendedInfo: { @@ -61,11 +61,11 @@ module.exports = [ }, }, 'appcache-manifest': { - score: false, + score: 0, debugString: 'Found .', }, 'geolocation-on-start': { - score: false, + score: 0, }, 'link-blocking-first-paint': { score: 0, @@ -84,7 +84,7 @@ module.exports = [ }, }, 'no-document-write': { - score: false, + score: 0, extendedInfo: { value: { length: 3, @@ -97,7 +97,7 @@ module.exports = [ }, }, 'no-mutation-events': { - score: false, + score: 0, extendedInfo: { value: { results: { @@ -112,7 +112,7 @@ module.exports = [ }, }, 'no-vulnerable-libraries': { - score: false, + score: 0, details: { items: { length: 1, @@ -120,14 +120,14 @@ module.exports = [ }, }, 'no-websql': { - score: false, + score: 0, debugString: 'Found database "mydb", version: 1.0.', }, 'notification-on-start': { - score: false, + score: 0, }, 'script-blocking-first-paint': { - score: '<100', + score: '<1', extendedInfo: { value: { results: { @@ -142,7 +142,7 @@ module.exports = [ }, }, 'uses-passive-event-listeners': { - score: false, + score: 0, extendedInfo: { value: { // Note: Originally this was 7 but M56 defaults document-level @@ -154,7 +154,7 @@ module.exports = [ }, }, 'deprecations': { - score: false, + score: 0, extendedInfo: { value: { length: 3, @@ -167,7 +167,7 @@ module.exports = [ }, }, 'password-inputs-can-be-pasted-into': { - score: false, + score: 0, extendedInfo: { value: { length: 2, @@ -175,7 +175,7 @@ module.exports = [ }, }, 'image-aspect-ratio': { - score: false, + score: 0, details: { items: { 0: { @@ -191,7 +191,7 @@ module.exports = [ url: 'http://localhost:10200/dobetterweb/domtester.html?smallDOM', audits: { 'dom-size': { - score: 100, + score: 1, extendedInfo: { value: { 0: {value: '1,324'}, @@ -235,7 +235,7 @@ module.exports = [ url: 'http://localhost:10200/dobetterweb/domtester.html?withShadowDOM', audits: { 'dom-size': { - score: 100, + score: 1, extendedInfo: { value: { 0: {value: '37'}, @@ -257,7 +257,7 @@ module.exports = [ url: 'http://localhost:10200/dobetterweb/domtester.html?ShadowRootWithManyChildren', audits: { 'dom-size': { - score: 100, + score: 1, extendedInfo: { value: { 0: {value: '33'}, @@ -279,40 +279,40 @@ module.exports = [ url: 'http://localhost:10200/online-only.html', audits: { 'is-on-https': { - score: true, + score: 1, }, 'uses-http2': { - score: false, + score: 0, }, 'external-anchors-use-rel-noopener': { - score: true, + score: 1, }, 'appcache-manifest': { - score: true, + score: 1, }, 'geolocation-on-start': { - score: true, + score: 1, }, 'link-blocking-first-paint': { - score: 100, + score: 1, }, 'no-document-write': { - score: true, + score: 1, }, 'no-mutation-events': { - score: true, + score: 1, }, 'no-websql': { - score: true, + score: 1, }, 'script-blocking-first-paint': { - score: 100, + score: 1, }, 'uses-passive-event-listeners': { - score: true, + score: 1, }, 'password-inputs-can-be-pasted-into': { - score: true, + score: 1, }, }, }, diff --git a/lighthouse-cli/test/smokehouse/offline-local/offline-expectations.js b/lighthouse-cli/test/smokehouse/offline-local/offline-expectations.js index 7d5baa5f4292..407bcfdfb262 100644 --- a/lighthouse-cli/test/smokehouse/offline-local/offline-expectations.js +++ b/lighthouse-cli/test/smokehouse/offline-local/offline-expectations.js @@ -16,39 +16,39 @@ module.exports = [ url: 'http://localhost:10200/online-only.html', audits: { 'is-on-https': { - score: true, + score: 1, }, 'redirects-http': { - score: false, + score: 0, }, 'service-worker': { - score: false, + score: 0, }, 'works-offline': { - score: false, + score: 0, }, 'viewport': { - score: true, + score: 1, }, 'without-javascript': { - score: true, + score: 1, }, 'user-timings': { - score: true, - displayValue: '0', + score: 1, + displayValue: '', }, 'critical-request-chains': { - score: true, - displayValue: '0', + score: 1, + displayValue: '', }, 'webapp-install-banner': { - score: false, + score: 0, }, 'splash-screen': { - score: false, + score: 0, }, 'themed-omnibox': { - score: false, + score: 0, }, 'aria-valid-attr': { notApplicable: true, @@ -57,7 +57,7 @@ module.exports = [ notApplicable: true, }, 'color-contrast': { - score: true, + score: 1, }, 'image-alt': { notApplicable: true, @@ -69,7 +69,7 @@ module.exports = [ notApplicable: true, }, 'content-width': { - score: true, + score: 1, }, }, }, @@ -79,39 +79,39 @@ module.exports = [ url: 'http://localhost:10503/offline-ready.html', audits: { 'is-on-https': { - score: true, + score: 1, }, 'redirects-http': { - score: false, + score: 0, }, 'service-worker': { - score: true, + score: 1, }, 'works-offline': { - score: true, + score: 1, }, 'viewport': { - score: true, + score: 1, }, 'without-javascript': { - score: true, + score: 1, }, 'user-timings': { - score: true, - displayValue: '0', + score: 1, + displayValue: '', }, 'critical-request-chains': { - score: true, - displayValue: '0', + score: 1, + displayValue: '', }, 'webapp-install-banner': { - score: false, + score: 0, }, 'splash-screen': { - score: false, + score: 0, }, 'themed-omnibox': { - score: false, + score: 0, }, 'aria-valid-attr': { notApplicable: true, @@ -120,10 +120,10 @@ module.exports = [ notApplicable: true, }, 'color-contrast': { - score: true, + score: 1, }, 'image-alt': { - score: false, + score: 0, }, 'label': { notApplicable: true, @@ -132,7 +132,7 @@ module.exports = [ notApplicable: true, }, 'content-width': { - score: true, + score: 1, }, }, }, diff --git a/lighthouse-cli/test/smokehouse/perf/expectations.js b/lighthouse-cli/test/smokehouse/perf/expectations.js index fa92030288e1..d85098e5c55c 100644 --- a/lighthouse-cli/test/smokehouse/perf/expectations.js +++ b/lighthouse-cli/test/smokehouse/perf/expectations.js @@ -14,7 +14,7 @@ module.exports = [ url: 'http://localhost:10200/preload.html', audits: { 'speed-index-metric': { - score: '>=80', + score: '>=0.80', extendedInfo: { value: { timings: {}, @@ -24,13 +24,13 @@ module.exports = [ }, }, 'first-meaningful-paint': { - score: '>=90', + score: '>=0.90', }, 'first-interactive': { - score: '>=90', + score: '>=0.90', }, 'consistently-interactive': { - score: '>=90', + score: '>=0.90', }, 'time-to-first-byte': { // Can be flaky, so test float rawValue instead of boolean score @@ -44,7 +44,7 @@ module.exports = [ }, }, 'uses-rel-preload': { - score: '<100', + score: '<1', rawValue: '>500', details: { items: { @@ -59,7 +59,7 @@ module.exports = [ url: 'http://localhost:10200/perf/fonts.html', audits: { 'font-display': { - score: false, + score: 0, rawValue: false, details: { items: { diff --git a/lighthouse-cli/test/smokehouse/pwa-expectations.js b/lighthouse-cli/test/smokehouse/pwa-expectations.js index b602b1224010..d0d32660b38c 100644 --- a/lighthouse-cli/test/smokehouse/pwa-expectations.js +++ b/lighthouse-cli/test/smokehouse/pwa-expectations.js @@ -15,28 +15,28 @@ module.exports = [ url: 'https://airhorner.com/', audits: { 'is-on-https': { - score: true, + score: 1, }, 'redirects-http': { - score: true, + score: 1, }, 'service-worker': { - score: true, + score: 1, }, 'works-offline': { - score: true, + score: 1, }, 'viewport': { - score: true, + score: 1, }, 'without-javascript': { - score: true, + score: 1, }, 'load-fast-enough-for-pwa': { // Ignore speed test; just verify that it ran. }, 'webapp-install-banner': { - score: true, + score: 1, extendedInfo: { value: { manifestValues: { @@ -56,7 +56,7 @@ module.exports = [ }, }, 'splash-screen': { - score: true, + score: 1, extendedInfo: { value: { manifestValues: { @@ -76,7 +76,7 @@ module.exports = [ }, }, 'themed-omnibox': { - score: true, + score: 1, extendedInfo: { value: { manifestValues: { @@ -96,20 +96,20 @@ module.exports = [ }, }, 'content-width': { - score: true, + score: 1, }, // "manual" audits. Just verify in the results. 'pwa-cross-browser': { - score: false, + score: 0, manual: true, }, 'pwa-page-transitions': { - score: false, + score: 0, manual: true, }, 'pwa-each-page-has-url': { - score: false, + score: 0, manual: true, }, }, @@ -120,28 +120,28 @@ module.exports = [ url: 'https://www.chromestatus.com/features', audits: { 'is-on-https': { - score: true, + score: 1, }, 'redirects-http': { - score: true, + score: 1, }, 'service-worker': { - score: true, + score: 1, }, 'works-offline': { - score: false, + score: 0, }, 'viewport': { - score: true, + score: 1, }, 'without-javascript': { - score: true, + score: 1, }, 'load-fast-enough-for-pwa': { // Ignore speed test; just verify that it ran. }, 'webapp-install-banner': { - score: false, + score: 0, extendedInfo: { value: { manifestValues: { @@ -161,7 +161,7 @@ module.exports = [ }, }, 'splash-screen': { - score: true, + score: 1, extendedInfo: { value: { manifestValues: { @@ -181,7 +181,7 @@ module.exports = [ }, }, 'themed-omnibox': { - score: true, + score: 1, extendedInfo: { value: { manifestValues: { @@ -201,20 +201,20 @@ module.exports = [ }, }, 'content-width': { - score: true, + score: 1, }, // "manual" audits. Just verify in the results. 'pwa-cross-browser': { - score: false, + score: 0, manual: true, }, 'pwa-page-transitions': { - score: false, + score: 0, manual: true, }, 'pwa-each-page-has-url': { - score: false, + score: 0, manual: true, }, }, @@ -225,30 +225,30 @@ module.exports = [ url: 'https://jakearchibald.github.io/svgomg/', audits: { 'is-on-https': { - score: true, + score: 1, }, 'redirects-http': { // Note: relies on JS redirect. // see https://github.com/GoogleChrome/lighthouse/issues/2383 - score: false, + score: 0, }, 'service-worker': { - score: true, + score: 1, }, 'works-offline': { - score: true, + score: 1, }, 'viewport': { - score: true, + score: 1, }, 'without-javascript': { - score: true, + score: 1, }, 'load-fast-enough-for-pwa': { // Ignore speed test; just verify that it ran. }, 'webapp-install-banner': { - score: false, + score: 0, extendedInfo: { value: { manifestValues: { @@ -268,7 +268,7 @@ module.exports = [ }, }, 'splash-screen': { - score: true, + score: 1, extendedInfo: { value: { manifestValues: { @@ -288,7 +288,7 @@ module.exports = [ }, }, 'themed-omnibox': { - score: true, + score: 1, extendedInfo: { value: { manifestValues: { @@ -308,20 +308,20 @@ module.exports = [ }, }, 'content-width': { - score: true, + score: 1, }, // "manual" audits. Just verify in the results. 'pwa-cross-browser': { - score: false, + score: 0, manual: true, }, 'pwa-page-transitions': { - score: false, + score: 0, manual: true, }, 'pwa-each-page-has-url': { - score: false, + score: 0, manual: true, }, }, @@ -334,28 +334,28 @@ module.exports = [ // url: 'https://shop.polymer-project.org/', // audits: { // 'is-on-https': { - // score: true + // score: 1 // }, // 'redirects-http': { - // score: true + // score: 1 // }, // 'service-worker': { - // score: true + // score: 1 // }, // 'works-offline': { - // score: true + // score: 1 // }, // 'viewport': { - // score: true + // score: 1 // }, // 'without-javascript': { - // score: true + // score: 1 // }, // 'load-fast-enough-for-pwa': { // // Ignore speed test; just verify that it ran. // }, // 'webapp-install-banner': { - // score: true, + // score: 1, // extendedInfo: { // value: { // manifestValues: { @@ -375,7 +375,7 @@ module.exports = [ // } // }, // 'splash-screen': { - // score: true, + // score: 1, // extendedInfo: { // value: { // manifestValues: { @@ -395,7 +395,7 @@ module.exports = [ // } // }, // 'themed-omnibox': { - // score: true, + // score: 1, // extendedInfo: { // value: { // manifestValues: { @@ -415,20 +415,20 @@ module.exports = [ // } // }, // 'content-width': { - // score: true + // score: 1 // }, // // "manual" audits. Just verify in the results. // 'pwa-cross-browser': { - // score: false, + // score: 0, // manual: true // }, // 'pwa-page-transitions': { - // score: false, + // score: 0, // manual: true // }, // 'pwa-each-page-has-url': { - // score: false, + // score: 0, // manual: true // } // } @@ -439,28 +439,28 @@ module.exports = [ url: 'https://pwa.rocks/', audits: { 'is-on-https': { - score: true, + score: 1, }, 'redirects-http': { - score: true, + score: 1, }, 'service-worker': { - score: true, + score: 1, }, 'works-offline': { - score: true, + score: 1, }, 'viewport': { - score: true, + score: 1, }, 'without-javascript': { - score: true, + score: 1, }, 'load-fast-enough-for-pwa': { // Ignore speed test; just verify that it ran . }, 'webapp-install-banner': { - score: true, + score: 1, extendedInfo: { value: { manifestValues: { @@ -480,7 +480,7 @@ module.exports = [ }, }, 'splash-screen': { - score: false, + score: 0, extendedInfo: { value: { manifestValues: { @@ -500,7 +500,7 @@ module.exports = [ }, }, 'themed-omnibox': { - score: false, + score: 0, extendedInfo: { value: { manifestValues: { @@ -520,20 +520,20 @@ module.exports = [ }, }, 'content-width': { - score: true, + score: 1, }, // "manual" audits. Just verify in the results. 'pwa-cross-browser': { - score: false, + score: 0, manual: true, }, 'pwa-page-transitions': { - score: false, + score: 0, manual: true, }, 'pwa-each-page-has-url': { - score: false, + score: 0, manual: true, }, }, diff --git a/lighthouse-cli/test/smokehouse/redirects/expectations.js b/lighthouse-cli/test/smokehouse/redirects/expectations.js index 9010d61156b4..085edd8e116e 100644 --- a/lighthouse-cli/test/smokehouse/redirects/expectations.js +++ b/lighthouse-cli/test/smokehouse/redirects/expectations.js @@ -16,7 +16,7 @@ module.exports = [ url: 'http://localhost:10200/redirects-final.html', audits: { 'redirects': { - score: '<100', + score: '<1', rawValue: '>=500', details: { items: { @@ -31,7 +31,7 @@ module.exports = [ url: 'http://localhost:10200/redirects-final.html', audits: { 'redirects': { - score: 100, + score: 1, rawValue: '>=250', details: { items: { diff --git a/lighthouse-cli/test/smokehouse/seo/expectations.js b/lighthouse-cli/test/smokehouse/seo/expectations.js index 700910196e55..2455258370e8 100644 --- a/lighthouse-cli/test/smokehouse/seo/expectations.js +++ b/lighthouse-cli/test/smokehouse/seo/expectations.js @@ -32,16 +32,16 @@ module.exports = [ url: BASE_URL + 'seo-tester.html', audits: { 'viewport': { - score: true, + score: 1, }, 'document-title': { - score: true, + score: 1, }, 'meta-description': { - score: true, + score: 1, }, 'http-status-code': { - score: true, + score: 1, }, 'font-size': { rawValue: true, @@ -52,19 +52,19 @@ module.exports = [ }, }, 'link-text': { - score: true, + score: 1, }, 'is-crawlable': { - score: true, + score: 1, }, 'hreflang': { - score: true, + score: 1, }, 'plugins': { - score: true, + score: 1, }, 'canonical': { - score: true, + score: 1, }, }, }, @@ -73,10 +73,10 @@ module.exports = [ url: BASE_URL + 'seo-failure-cases.html?status_code=403&' + failureHeaders, audits: { 'viewport': { - score: false, + score: 0, }, 'document-title': { - score: false, + score: 0, extendedInfo: { value: { id: 'document-title', @@ -84,10 +84,10 @@ module.exports = [ }, }, 'meta-description': { - score: false, + score: 0, }, 'http-status-code': { - score: false, + score: 0, displayValue: '403', }, 'font-size': { @@ -95,7 +95,7 @@ module.exports = [ debugString: 'Text is illegible because of a missing viewport config', }, 'link-text': { - score: false, + score: 0, displayValue: '3 links found', details: { items: { @@ -104,7 +104,7 @@ module.exports = [ }, }, 'is-crawlable': { - score: false, + score: 0, details: { items: { length: 2, @@ -112,7 +112,7 @@ module.exports = [ }, }, 'hreflang': { - score: false, + score: 0, details: { items: { length: 3, @@ -120,7 +120,7 @@ module.exports = [ }, }, 'plugins': { - score: false, + score: 0, details: { items: { length: 3, @@ -128,7 +128,7 @@ module.exports = [ }, }, 'canonical': { - score: false, + score: 0, debugString: 'Multiple URLs (https://example.com, https://example.com/)', }, }, diff --git a/lighthouse-cli/test/smokehouse/smokehouse.js b/lighthouse-cli/test/smokehouse/smokehouse.js index 2861cb538c44..76613b1db7b2 100755 --- a/lighthouse-cli/test/smokehouse/smokehouse.js +++ b/lighthouse-cli/test/smokehouse/smokehouse.js @@ -18,7 +18,7 @@ const DEFAULT_EXPECTATIONS_PATH = 'pwa-expectations'; const PROTOCOL_TIMEOUT_EXIT_CODE = 67; const RETRIES = 3; -const NUMERICAL_EXPECTATION_REGEXP = /^(<=?|>=?)(\d+)$/; +const NUMERICAL_EXPECTATION_REGEXP = /^(<=?|>=?)((\d|\.)+)$/; /** @@ -97,7 +97,7 @@ function matchesExpectation(actual, expected) { if (typeof actual === 'number' && NUMERICAL_EXPECTATION_REGEXP.test(expected)) { const parts = expected.match(NUMERICAL_EXPECTATION_REGEXP); const operator = parts[1]; - const number = parseInt(parts[2]); + const number = parseFloat(parts[2]); switch (operator) { case '>': return actual > number; diff --git a/lighthouse-core/audits/accessibility/axe-audit.js b/lighthouse-core/audits/accessibility/axe-audit.js index c160dd8df4e4..14182df4c3b1 100644 --- a/lighthouse-core/audits/accessibility/axe-audit.js +++ b/lighthouse-core/audits/accessibility/axe-audit.js @@ -26,7 +26,7 @@ class AxeAudit extends Audit { const isNotApplicable = notApplicables.find(result => result.id === this.meta.name); if (isNotApplicable) { return { - rawValue: false, + rawValue: true, notApplicable: true, }; } diff --git a/lighthouse-core/audits/audit.js b/lighthouse-core/audits/audit.js index ae179e191697..dfd7d9020b30 100644 --- a/lighthouse-core/audits/audit.js +++ b/lighthouse-core/audits/audit.js @@ -10,6 +10,13 @@ const statistics = require('../lib/statistics'); const DEFAULT_PASS = 'defaultPass'; +/** + * Clamp figure to 2 decimal places + * @param {number} val + * @return {number} + */ +const clampTo2Decimals = val => Math.round(val * 100) / 100; + class Audit { /** * @return {!string} @@ -51,10 +58,10 @@ class Audit { diminishingReturnsValue ); - let score = 100 * distribution.computeComplementaryPercentile(measuredValue); - score = Math.min(100, score); + let score = distribution.computeComplementaryPercentile(measuredValue); + score = Math.min(1, score); score = Math.max(0, score); - return Math.round(score); + return clampTo2Decimals(score); } /** @@ -94,6 +101,29 @@ class Audit { }; } + /** + * @param {!Audit} audit + * @param {!AuditResult} result + * @return {{score: number, scoreDisplayMode: string}} + */ + static _normalizeAuditScore(audit, result) { + // Cast true/false to 1/0 + let score = result.score === undefined ? Number(result.rawValue) : result.score; + + if (!Number.isFinite(score)) throw new Error(`Invalid score: ${score}`); + if (score > 1) throw new Error(`Audit score for ${audit.meta.name} is > 1`); + if (score < 0) throw new Error(`Audit score for ${audit.meta.name} is < 0`); + + score = clampTo2Decimals(score); + + const scoreDisplayMode = audit.meta.scoreDisplayMode || Audit.SCORING_MODES.BINARY; + + return { + score, + scoreDisplayMode, + }; + } + /** * @param {!Audit} audit * @param {!AuditResult} result @@ -104,31 +134,35 @@ class Audit { throw new Error('generateAuditResult requires a rawValue'); } - const score = typeof result.score === 'undefined' ? result.rawValue : result.score; - let displayValue = result.displayValue; - if (typeof displayValue === 'undefined') { - displayValue = result.rawValue ? result.rawValue : ''; - } + // eslint-disable-next-line prefer-const + let {score, scoreDisplayMode} = Audit._normalizeAuditScore(audit, result); - // The same value or true should be '' it doesn't add value to the report - if (displayValue === score) { - displayValue = ''; + // If the audit was determined to not apply to the page, we'll reset it as informative only + let informative = audit.meta.informative; + if (result.notApplicable) { + score = 1; + informative = true; + result.rawValue = true; } + + const displayValue = result.displayValue ? `${result.displayValue}` : ''; + let auditDescription = audit.meta.description; if (audit.meta.failureDescription) { - if (!score || (typeof score === 'number' && score < 100)) { + if (score < 1) { auditDescription = audit.meta.failureDescription; } } + return { score, - displayValue: `${displayValue}`, + displayValue, rawValue: result.rawValue, error: result.error, debugString: result.debugString, extendedInfo: result.extendedInfo, - scoringMode: audit.meta.scoringMode || Audit.SCORING_MODES.BINARY, - informative: audit.meta.informative, + scoreDisplayMode, + informative, manual: audit.meta.manual, notApplicable: result.notApplicable, name: audit.meta.name, diff --git a/lighthouse-core/audits/bootup-time.js b/lighthouse-core/audits/bootup-time.js index 16e8aaf5de0a..dc53175e781e 100644 --- a/lighthouse-core/audits/bootup-time.js +++ b/lighthouse-core/audits/bootup-time.js @@ -99,7 +99,7 @@ class BootupTime extends Audit { const details = BootupTime.makeTableDetails(headings, results, summary); return { - score: totalBootupTime < 2000, + score: Number(totalBootupTime < 2000), rawValue: totalBootupTime, displayValue: Util.formatMilliseconds(totalBootupTime), details, diff --git a/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js b/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js index 68daeb91fc79..209e497a47ef 100644 --- a/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +++ b/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js @@ -24,9 +24,9 @@ class UnusedBytes extends Audit { * @return {number} */ static scoreForWastedMs(wastedMs) { - if (wastedMs === 0) return 100; - else if (wastedMs < WASTED_MS_FOR_AVERAGE) return 90; - else if (wastedMs < WASTED_MS_FOR_POOR) return 65; + if (wastedMs === 0) return 1; + else if (wastedMs < WASTED_MS_FOR_AVERAGE) return 0.9; + else if (wastedMs < WASTED_MS_FOR_POOR) return 0.65; else return 0; } diff --git a/lighthouse-core/audits/byte-efficiency/offscreen-images.js b/lighthouse-core/audits/byte-efficiency/offscreen-images.js index a874a7edb892..fcc52ad47d2e 100644 --- a/lighthouse-core/audits/byte-efficiency/offscreen-images.js +++ b/lighthouse-core/audits/byte-efficiency/offscreen-images.js @@ -28,6 +28,7 @@ class OffscreenImages extends ByteEfficiencyAudit { name: 'offscreen-images', description: 'Offscreen images', informative: true, + scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC, helpText: 'Consider lazy-loading offscreen and hidden images to improve page load speed ' + 'and time to interactive. ' + diff --git a/lighthouse-core/audits/byte-efficiency/total-byte-weight.js b/lighthouse-core/audits/byte-efficiency/total-byte-weight.js index 407f77e0fa03..b7680894fb7e 100644 --- a/lighthouse-core/audits/byte-efficiency/total-byte-weight.js +++ b/lighthouse-core/audits/byte-efficiency/total-byte-weight.js @@ -22,11 +22,11 @@ class TotalByteWeight extends ByteEfficiencyAudit { name: 'total-byte-weight', description: 'Avoids enormous network payloads', failureDescription: 'Has enormous network payloads', + scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC, helpText: 'Large network payloads cost users real money and are highly correlated with ' + 'long load times. [Learn ' + 'more](https://developers.google.com/web/tools/lighthouse/audits/network-payloads).', - scoringMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC, requiredArtifacts: ['devtoolsLogs'], }; } @@ -61,8 +61,8 @@ class TotalByteWeight extends ByteEfficiencyAudit { results = results.sort((itemA, itemB) => itemB.totalBytes - itemA.totalBytes).slice(0, 10); // Use the CDF of a log-normal distribution for scoring. - // <= 1600KB: score≈100 - // 4000KB: score=50 + // <= 1600KB: score≈1 + // 4000KB: score=0.50 // >= 9000KB: score≈0 const score = ByteEfficiencyAudit.computeLogNormalScore( totalBytes, diff --git a/lighthouse-core/audits/byte-efficiency/unminified-css.js b/lighthouse-core/audits/byte-efficiency/unminified-css.js index 220de0646a8f..5b97741f8f3e 100644 --- a/lighthouse-core/audits/byte-efficiency/unminified-css.js +++ b/lighthouse-core/audits/byte-efficiency/unminified-css.js @@ -23,6 +23,7 @@ class UnminifiedCSS extends ByteEfficiencyAudit { name: 'unminified-css', description: 'Minify CSS', informative: true, + scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC, helpText: 'Minifying CSS files can reduce network payload sizes. ' + '[Learn more](https://developers.google.com/speed/docs/insights/MinifyResources).', requiredArtifacts: ['CSSUsage', 'devtoolsLogs'], diff --git a/lighthouse-core/audits/byte-efficiency/unminified-javascript.js b/lighthouse-core/audits/byte-efficiency/unminified-javascript.js index 9a71397d81c4..c53c4badce75 100644 --- a/lighthouse-core/audits/byte-efficiency/unminified-javascript.js +++ b/lighthouse-core/audits/byte-efficiency/unminified-javascript.js @@ -30,6 +30,7 @@ class UnminifiedJavaScript extends ByteEfficiencyAudit { name: 'unminified-javascript', description: 'Minify JavaScript', informative: true, + scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC, helpText: 'Minifying JavaScript files can reduce payload sizes and script parse time. ' + '[Learn more](https://developers.google.com/speed/docs/insights/MinifyResources).', requiredArtifacts: ['Scripts', 'devtoolsLogs'], diff --git a/lighthouse-core/audits/byte-efficiency/unused-css-rules.js b/lighthouse-core/audits/byte-efficiency/unused-css-rules.js index 68ed1033c0a4..c054cd7cea27 100644 --- a/lighthouse-core/audits/byte-efficiency/unused-css-rules.js +++ b/lighthouse-core/audits/byte-efficiency/unused-css-rules.js @@ -19,6 +19,7 @@ class UnusedCSSRules extends ByteEfficiencyAudit { name: 'unused-css-rules', description: 'Unused CSS rules', informative: true, + scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC, helpText: 'Remove unused rules from stylesheets to reduce unnecessary ' + 'bytes consumed by network activity. ' + '[Learn more](https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery)', diff --git a/lighthouse-core/audits/byte-efficiency/unused-javascript.js b/lighthouse-core/audits/byte-efficiency/unused-javascript.js index cf6fd07a39b9..84b15894296b 100644 --- a/lighthouse-core/audits/byte-efficiency/unused-javascript.js +++ b/lighthouse-core/audits/byte-efficiency/unused-javascript.js @@ -18,6 +18,7 @@ class UnusedJavaScript extends ByteEfficiencyAudit { name: 'unused-javascript', description: 'Unused JavaScript', informative: true, + scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC, helpText: 'Remove unused JavaScript to reduce bytes consumed by network activity.', requiredArtifacts: ['JsUsage', 'devtoolsLogs'], }; diff --git a/lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js b/lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js index dd4618006442..ffa1abbd914a 100644 --- a/lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js +++ b/lighthouse-core/audits/byte-efficiency/uses-long-cache-ttl.js @@ -31,7 +31,7 @@ class CacheHeaders extends Audit { helpText: 'A long cache lifetime can speed up repeat visits to your page. ' + '[Learn more](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#cache-control).', - scoringMode: Audit.SCORING_MODES.NUMERIC, + scoreDisplayMode: Audit.SCORING_MODES.NUMERIC, requiredArtifacts: ['devtoolsLogs'], }; } @@ -206,9 +206,9 @@ class CacheHeaders extends Audit { ); // Use the CDF of a log-normal distribution for scoring. - // <= 4KB: score≈100 - // 768KB: score=50 - // >= 4600KB: score≈5 + // <= 4KB: score≈1 + // 768KB: score=0.5 + // >= 4600KB: score≈0.05 const score = Audit.computeLogNormalScore( totalWastedBytes / 1024, SCORING_POINT_OF_DIMINISHING_RETURNS, diff --git a/lighthouse-core/audits/byte-efficiency/uses-optimized-images.js b/lighthouse-core/audits/byte-efficiency/uses-optimized-images.js index 2aff63451945..4c2c5d4d3736 100644 --- a/lighthouse-core/audits/byte-efficiency/uses-optimized-images.js +++ b/lighthouse-core/audits/byte-efficiency/uses-optimized-images.js @@ -23,6 +23,7 @@ class UsesOptimizedImages extends ByteEfficiencyAudit { name: 'uses-optimized-images', description: 'Optimize images', informative: true, + scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC, helpText: 'Optimized images load faster and consume less cellular data. ' + '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/optimize-images).', requiredArtifacts: ['OptimizedImages', 'devtoolsLogs'], diff --git a/lighthouse-core/audits/byte-efficiency/uses-request-compression.js b/lighthouse-core/audits/byte-efficiency/uses-request-compression.js index 60bb718a3a56..117ad9d0636f 100644 --- a/lighthouse-core/audits/byte-efficiency/uses-request-compression.js +++ b/lighthouse-core/audits/byte-efficiency/uses-request-compression.js @@ -23,6 +23,7 @@ class ResponsesAreCompressed extends ByteEfficiencyAudit { return { name: 'uses-request-compression', informative: true, + scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC, description: 'Enable text compression', helpText: 'Text-based responses should be served with compression (gzip, deflate or brotli)' + ' to minimize total network bytes.' + diff --git a/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js b/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js index cd6c0ddabb2d..bbe4ff711e11 100644 --- a/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +++ b/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js @@ -29,6 +29,7 @@ class UsesResponsiveImages extends ByteEfficiencyAudit { name: 'uses-responsive-images', description: 'Properly size images', informative: true, + scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC, helpText: 'Serve images that are appropriately-sized to save cellular data ' + 'and improve load time. ' + diff --git a/lighthouse-core/audits/byte-efficiency/uses-webp-images.js b/lighthouse-core/audits/byte-efficiency/uses-webp-images.js index ad5b6a8d991d..00ca938a9c5f 100644 --- a/lighthouse-core/audits/byte-efficiency/uses-webp-images.js +++ b/lighthouse-core/audits/byte-efficiency/uses-webp-images.js @@ -23,6 +23,7 @@ class UsesWebPImages extends ByteEfficiencyAudit { name: 'uses-webp-images', description: 'Serve images in next-gen formats', informative: true, + scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.NUMERIC, helpText: 'Image formats like JPEG 2000, JPEG XR, and WebP often provide better ' + 'compression than PNG or JPEG, which means faster downloads and less data consumption. ' + '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/webp).', diff --git a/lighthouse-core/audits/consistently-interactive.js b/lighthouse-core/audits/consistently-interactive.js index 8324ed553bc0..6933482443ab 100644 --- a/lighthouse-core/audits/consistently-interactive.js +++ b/lighthouse-core/audits/consistently-interactive.js @@ -36,7 +36,7 @@ class ConsistentlyInteractiveMetric extends Audit { helpText: 'Consistently Interactive marks the time at which the page is ' + 'fully interactive. ' + '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive).', - scoringMode: Audit.SCORING_MODES.NUMERIC, + scoreDisplayMode: Audit.SCORING_MODES.NUMERIC, requiredArtifacts: ['traces', 'devtoolsLogs'], }; } diff --git a/lighthouse-core/audits/critical-request-chains.js b/lighthouse-core/audits/critical-request-chains.js index fc52080a0bb6..fbb187e369f5 100644 --- a/lighthouse-core/audits/critical-request-chains.js +++ b/lighthouse-core/audits/critical-request-chains.js @@ -117,7 +117,7 @@ class CriticalRequestChains extends Audit { /** * Audits the page to give a score for First Meaningful Paint. * @param {!Artifacts} artifacts The artifacts from the gather phase. - * @return {!AuditResult} The score from the audit, ranging from 0-100. + * @return {!AuditResult} */ static audit(artifacts) { const devtoolsLogs = artifacts.devtoolsLogs[Audit.DEFAULT_PASS]; @@ -151,7 +151,7 @@ class CriticalRequestChains extends Audit { return { rawValue: chainCount === 0, - displayValue: Util.formatNumber(chainCount), + displayValue: chainCount ? `${Util.formatNumber(chainCount)} chains found`: '', extendedInfo: { value: { chains: flattenedChains, diff --git a/lighthouse-core/audits/dobetterweb/dom-size.js b/lighthouse-core/audits/dobetterweb/dom-size.js index e0f76da76cca..5e7dcaa0a9a8 100644 --- a/lighthouse-core/audits/dobetterweb/dom-size.js +++ b/lighthouse-core/audits/dobetterweb/dom-size.js @@ -42,7 +42,7 @@ class DOMSize extends Audit { 'children/parent element. A large DOM can increase memory usage, cause longer ' + '[style calculations](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), ' + 'and produce costly [layout reflows](https://developers.google.com/speed/articles/reflow). [Learn more](https://developers.google.com/web/fundamentals/performance/rendering/).', - scoringMode: Audit.SCORING_MODES.NUMERIC, + scoreDisplayMode: Audit.SCORING_MODES.NUMERIC, requiredArtifacts: ['DOMStats'], }; } @@ -67,8 +67,8 @@ class DOMSize extends Audit { stats.width.pathToElement[stats.width.pathToElement.length - 1]; // Use the CDF of a log-normal distribution for scoring. - // <= 1500: score≈100 - // 3000: score=50 + // <= 1500: score≈1 + // 3000: score=0.5 // >= 5970: score≈0 const score = Audit.computeLogNormalScore( stats.totalDOMNodes, diff --git a/lighthouse-core/audits/dobetterweb/link-blocking-first-paint.js b/lighthouse-core/audits/dobetterweb/link-blocking-first-paint.js index 79317351efe9..6deecbd6dd66 100644 --- a/lighthouse-core/audits/dobetterweb/link-blocking-first-paint.js +++ b/lighthouse-core/audits/dobetterweb/link-blocking-first-paint.js @@ -29,6 +29,7 @@ class LinkBlockingFirstPaintAudit extends Audit { name: 'link-blocking-first-paint', description: 'Reduce render-blocking stylesheets', informative: true, + scoreDisplayMode: Audit.SCORING_MODES.NUMERIC, helpText: 'External stylesheets are blocking the first paint of your page. Consider ' + 'delivering critical CSS via `