Repository: GoogleChrome/lighthouse
Pull request #10623 (2020-04-23 00:24:36)

report: add Trust & Safety group under Best Practices
As the title suggests, this PR simply moves the Trust and Safety related audits to a specified sub-category. All other Best Practices audits are moved under General.

<img width="1044" alt="Screen Shot 2020-04-22 at 5 18 48 PM" src="https://user-images.githubusercontent.com/27858957/80046008-1b022700-84be-11ea-9fb7-3d85de5a37a6.png">


brendankenny: are ungrouped audits still a thing? Is it better to have everything else under 'General' or to just have them be ungrouped?

I don't have a strong opinion, but generally using up UI space just to have a generic "other things" title doesn't add that much. OTOH maybe it doesn't look so great not grouped :)
brendankenny: > are ungrouped audits still a thing?

oh, looks like [ungrouped ones come first](https://github.com/GoogleChrome/lighthouse/blob/57a3048d3bf861e992a7ca6814ca0f873dee2d53/lighthouse-core/report/html/renderer/category-renderer.js#L410-L427) which wouldn't be great for this. What great ascii art someone put in that comment, though!

I guess the order could be reversed, but OTOH here is @patrickhulce arguing for the exact opposite of "minimum amount of groups pls" :)
Beytoven: > > are ungrouped audits still a thing?
> 
> oh, looks like [ungrouped ones come first](https://github.com/GoogleChrome/lighthouse/blob/57a3048d3bf861e992a7ca6814ca0f873dee2d53/lighthouse-core/report/html/renderer/category-renderer.js#L410-L427) which wouldn't be great for this. What great ascii art someone put in that comment, though!
> 
> I guess the order could be reversed, but OTOH here is @patrickhulce arguing for the exact opposite of "minimum amount of groups pls" :)

The styling doesn't look too good with a mix of grouped and ungrouped audits.

For reference:
<img width="1214" alt="Screen Shot 2020-04-22 at 5 04 35 PM" src="https://user-images.githubusercontent.com/27858957/80147787-e13a2a80-8568-11ea-8d78-c132b202f81a.png">

patrickhulce: @brendankenny did you wish to have another look or are you fine with my LGTM?

Patch:
diff --git a/lighthouse-core/audits/dobetterweb/no-document-write.js b/lighthouse-core/audits/dobetterweb/no-document-write.js
index 1aff3d12c..3144371bc 100644
--- a/lighthouse-core/audits/dobetterweb/no-document-write.js
+++ b/lighthouse-core/audits/dobetterweb/no-document-write.js
@@ -34,8 +34,8 @@ const i18n = require('../../lib/i18n/i18n.js');
 const UIStrings = {
   /** Title of a Lighthouse audit that provides detail on the page's use of the `document.write` API. This descriptive title is shown to users when the page does not use `document.write`. */
   title: 'Avoids `document.write()`',
-  /** Title of a Lighthouse audit that provides detail on the page's use of the `document.write` API. This descriptive title is shown to users when the page does use `document.write`. */
-  failureTitle: 'Uses `document.write()`',
+  /** Title of a Lighthouse audit that provides detail on the page's use of the `document.write` API. This imperative title is shown to users when the page does use `document.write`. */
+  failureTitle: 'Avoid `document.write()`',
   /** Description of a Lighthouse audit that tells the user why they should avoid `document.write`. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */
   description: 'For users on slow connections, external scripts dynamically injected via ' +
       '`document.write()` can delay page load by tens of seconds. ' +
diff --git a/lighthouse-core/config/default-config.js b/lighthouse-core/config/default-config.js
index b1f282c1c..b0db22695 100644
--- a/lighthouse-core/config/default-config.js
+++ b/lighthouse-core/config/default-config.js
@@ -105,6 +105,14 @@ const UIStrings = {
   'not automatically checked by Lighthouse. They do not affect your score but it\'s important that you verify them manually.',
   /** Title of the Best Practices category of audits. This is displayed at the top of a list of audits focused on topics related to following web development best practices and accepted guidelines. Also used as a label of a score gauge; try to limit to 20 characters. */
   bestPracticesCategoryTitle: 'Best Practices',
+  /** Title of the Trust & Safety group of audits. This is displayed at the top of a list of audits focused on maintaining user trust and protecting security in web development. */
+  bestPracticesTrustSafetyGroupTitle: 'Trust and Safety',
+  /** Title of the User Experience group of the Best Practices category. Within this section are the audits related to the end user's experience of the webpage. */
+  bestPracticesUXGroupTitle: 'User Experience',
+  /** Title of the Browser Compatibility group of the Best Practices category. Within this section are the audits related to whether the page is interpreted consistently by browsers. */
+  bestPracticesBrowserCompatGroupTitle: 'Browser Compatibility',
+  /** Title of the General group of the Best Practices category. Within this section are the audits that don't belong to a specific group but are of general interest. */
+  bestPracticesGeneralGroupTitle: 'General',
   /** Title of the Fast and Reliable section of the web app category. Within this section are audits that check if the web site loaded quickly and can reliably load even if the internet connection is very slow or goes offline. */
   pwaFastReliableGroupTitle: 'Fast and reliable',
   /** Title of the Installable section of the web app category. Within this section are audits that check if Chrome supports installing the web site as an app on their device. */
@@ -384,6 +392,18 @@ const defaultConfig = {
       title: str_(UIStrings.seoCrawlingGroupTitle),
       description: str_(UIStrings.seoCrawlingGroupDescription),
     },
+    'best-practices-trust-safety': {
+      title: str_(UIStrings.bestPracticesTrustSafetyGroupTitle),
+    },
+    'best-practices-ux': {
+      title: str_(UIStrings.bestPracticesUXGroupTitle),
+    },
+    'best-practices-browser-compat': {
+      title: str_(UIStrings.bestPracticesBrowserCompatGroupTitle),
+    },
+    'best-practices-general': {
+      title: str_(UIStrings.bestPracticesGeneralGroupTitle),
+    },
   },
   categories: {
     'performance': {
@@ -428,6 +448,9 @@ const defaultConfig = {
         {id: 'timing-budget', weight: 0, group: 'budgets'},
         {id: 'resource-summary', weight: 0, group: 'diagnostics'},
         {id: 'third-party-summary', weight: 0, group: 'diagnostics'},
+        {id: 'uses-http2', weight: 0, group: 'diagnostics'},
+        {id: 'uses-passive-event-listeners', weight: 0, group: 'diagnostics'},
+        {id: 'no-document-write', weight: 0, group: 'diagnostics'},
         // Audits past this point don't belong to a group and will not be shown automatically
         {id: 'network-requests', weight: 0},
         {id: 'network-rtt', weight: 0},
@@ -505,23 +528,24 @@ const defaultConfig = {
     'best-practices': {
       title: str_(UIStrings.bestPracticesCategoryTitle),
       auditRefs: [
-        {id: 'appcache-manifest', weight: 1},
-        {id: 'is-on-https', weight: 1},
-        {id: 'uses-http2', weight: 1},
-        {id: 'uses-passive-event-listeners', weight: 1},
-        {id: 'no-document-write', weight: 1},
-        {id: 'external-anchors-use-rel-noopener', weight: 1},
-        {id: 'geolocation-on-start', weight: 1},
-        {id: 'doctype', weight: 1},
-        {id: 'charset', weight: 1},
-        {id: 'no-vulnerable-libraries', weight: 1},
-        {id: 'js-libraries', weight: 0},
-        {id: 'notification-on-start', weight: 1},
-        {id: 'deprecations', weight: 1},
-        {id: 'password-inputs-can-be-pasted-into', weight: 1},
-        {id: 'errors-in-console', weight: 1},
-        {id: 'image-aspect-ratio', weight: 1},
-        {id: 'image-size-responsive', weight: 1},
+        // Trust & Safety
+        {id: 'is-on-https', weight: 1, group: 'best-practices-trust-safety'},
+        {id: 'external-anchors-use-rel-noopener', weight: 1, group: 'best-practices-trust-safety'},
+        {id: 'geolocation-on-start', weight: 1, group: 'best-practices-trust-safety'},
+        {id: 'notification-on-start', weight: 1, group: 'best-practices-trust-safety'},
+        {id: 'no-vulnerable-libraries', weight: 1, group: 'best-practices-trust-safety'},
+        // User Experience
+        {id: 'password-inputs-can-be-pasted-into', weight: 1, group: 'best-practices-ux'},
+        {id: 'image-aspect-ratio', weight: 1, group: 'best-practices-ux'},
+        {id: 'image-size-responsive', weight: 1, group: 'best-practices-ux'},
+        // Browser Compatibility
+        {id: 'doctype', weight: 1, group: 'best-practices-browser-compat'},
+        {id: 'charset', weight: 1, group: 'best-practices-browser-compat'},
+        // General Group
+        {id: 'appcache-manifest', weight: 1, group: 'best-practices-general'},
+        {id: 'js-libraries', weight: 0, group: 'best-practices-general'},
+        {id: 'deprecations', weight: 1, group: 'best-practices-general'},
+        {id: 'errors-in-console', weight: 1, group: 'best-practices-general'},
       ],
     },
     'seo': {
diff --git a/lighthouse-core/lib/i18n/locales/en-US.json b/lighthouse-core/lib/i18n/locales/en-US.json
index 086a81467..477a7c0a1 100644
--- a/lighthouse-core/lib/i18n/locales/en-US.json
+++ b/lighthouse-core/lib/i18n/locales/en-US.json
@@ -648,7 +648,7 @@
     "message": "For users on slow connections, external scripts dynamically injected via `document.write()` can delay page load by tens of seconds. [Learn more](https://web.dev/no-document-write)."
   },
   "lighthouse-core/audits/dobetterweb/no-document-write.js | failureTitle": {
-    "message": "Uses `document.write()`"
+    "message": "Avoid `document.write()`"
   },
   "lighthouse-core/audits/dobetterweb/no-document-write.js | title": {
     "message": "Avoids `document.write()`"
@@ -1325,9 +1325,21 @@
   "lighthouse-core/config/default-config.js | a11yTablesListsVideoGroupTitle": {
     "message": "Tables and lists"
   },
+  "lighthouse-core/config/default-config.js | bestPracticesBrowserCompatGroupTitle": {
+    "message": "Browser Compatibility"
+  },
   "lighthouse-core/config/default-config.js | bestPracticesCategoryTitle": {
     "message": "Best Practices"
   },
+  "lighthouse-core/config/default-config.js | bestPracticesGeneralGroupTitle": {
+    "message": "General"
+  },
+  "lighthouse-core/config/default-config.js | bestPracticesTrustSafetyGroupTitle": {
+    "message": "Trust and Safety"
+  },
+  "lighthouse-core/config/default-config.js | bestPracticesUXGroupTitle": {
+    "message": "User Experience"
+  },
   "lighthouse-core/config/default-config.js | budgetsGroupDescription": {
     "message": "Performance budgets set standards for the performance of your site."
   },
diff --git a/lighthouse-core/lib/i18n/locales/en-XL.json b/lighthouse-core/lib/i18n/locales/en-XL.json
index cc845329f..6af1a32a6 100644
--- a/lighthouse-core/lib/i18n/locales/en-XL.json
+++ b/lighthouse-core/lib/i18n/locales/en-XL.json
@@ -648,7 +648,7 @@
     "message": "F̂ór̂ úŝér̂ś ôń ŝĺôẃ ĉón̂ńêćt̂íôńŝ, éx̂t́êŕn̂ál̂ śĉŕîṕt̂ś d̂ýn̂ám̂íĉál̂ĺŷ ín̂j́êćt̂éd̂ v́îá `document.write()` ĉán̂ d́êĺâý p̂áĝé l̂óâd́ b̂ý t̂én̂ś ôf́ ŝéĉón̂d́ŝ. [Ĺêár̂ń m̂ór̂é](https://web.dev/no-document-write)."
   },
   "lighthouse-core/audits/dobetterweb/no-document-write.js | failureTitle": {
-    "message": "Ûśêś `document.write()`"
+    "message": "Âv́ôíd̂ `document.write()`"
   },
   "lighthouse-core/audits/dobetterweb/no-document-write.js | title": {
     "message": "Âv́ôíd̂ś `document.write()`"
@@ -1325,9 +1325,21 @@
   "lighthouse-core/config/default-config.js | a11yTablesListsVideoGroupTitle": {
     "message": "T̂áb̂ĺêś âńd̂ ĺîśt̂ś"
   },
+  "lighthouse-core/config/default-config.js | bestPracticesBrowserCompatGroupTitle": {
+    "message": "B̂ŕôẃŝér̂ Ćôḿp̂át̂íb̂íl̂ít̂ý"
+  },
   "lighthouse-core/config/default-config.js | bestPracticesCategoryTitle": {
     "message": "B̂éŝt́ P̂ŕâćt̂íĉéŝ"
   },
+  "lighthouse-core/config/default-config.js | bestPracticesGeneralGroupTitle": {
+    "message": "Ĝén̂ér̂ál̂"
+  },
+  "lighthouse-core/config/default-config.js | bestPracticesTrustSafetyGroupTitle": {
+    "message": "T̂ŕûśt̂ án̂d́ Ŝáf̂ét̂ý"
+  },
+  "lighthouse-core/config/default-config.js | bestPracticesUXGroupTitle": {
+    "message": "Ûśêŕ Êx́p̂ér̂íêńĉé"
+  },
   "lighthouse-core/config/default-config.js | budgetsGroupDescription": {
     "message": "P̂ér̂f́ôŕm̂án̂ćê b́ûd́ĝét̂ś ŝét̂ śt̂án̂d́âŕd̂ś f̂ór̂ t́ĥé p̂ér̂f́ôŕm̂án̂ćê óf̂ ýôúr̂ śît́ê."
   },


Test patch:
diff --git a/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap b/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap
index e106723d1..86441b7a2 100644
--- a/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap
+++ b/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap
@@ -680,73 +680,75 @@ Object {
     "best-practices": Object {
       "auditRefs": Array [
         Object {
-          "id": "appcache-manifest",
+          "group": "best-practices-trust-safety",
+          "id": "is-on-https",
           "weight": 1,
         },
         Object {
-          "id": "is-on-https",
+          "group": "best-practices-trust-safety",
+          "id": "external-anchors-use-rel-noopener",
           "weight": 1,
         },
         Object {
-          "id": "uses-http2",
+          "group": "best-practices-trust-safety",
+          "id": "geolocation-on-start",
           "weight": 1,
         },
         Object {
-          "id": "uses-passive-event-listeners",
+          "group": "best-practices-trust-safety",
+          "id": "notification-on-start",
           "weight": 1,
         },
         Object {
-          "id": "no-document-write",
+          "group": "best-practices-trust-safety",
+          "id": "no-vulnerable-libraries",
           "weight": 1,
         },
         Object {
-          "id": "external-anchors-use-rel-noopener",
+          "group": "best-practices-ux",
+          "id": "password-inputs-can-be-pasted-into",
           "weight": 1,
         },
         Object {
-          "id": "geolocation-on-start",
+          "group": "best-practices-ux",
+          "id": "image-aspect-ratio",
+          "weight": 1,
+        },
+        Object {
+          "group": "best-practices-ux",
+          "id": "image-size-responsive",
           "weight": 1,
         },
         Object {
+          "group": "best-practices-browser-compat",
           "id": "doctype",
           "weight": 1,
         },
         Object {
+          "group": "best-practices-browser-compat",
           "id": "charset",
           "weight": 1,
         },
         Object {
-          "id": "no-vulnerable-libraries",
+          "group": "best-practices-general",
+          "id": "appcache-manifest",
           "weight": 1,
         },
         Object {
+          "group": "best-practices-general",
           "id": "js-libraries",
           "weight": 0,
         },
         Object {
-          "id": "notification-on-start",
-          "weight": 1,
-        },
-        Object {
+          "group": "best-practices-general",
           "id": "deprecations",
           "weight": 1,
         },
         Object {
-          "id": "password-inputs-can-be-pasted-into",
-          "weight": 1,
-        },
-        Object {
+          "group": "best-practices-general",
           "id": "errors-in-console",
           "weight": 1,
         },
-        Object {
-          "id": "image-aspect-ratio",
-          "weight": 1,
-        },
-        Object {
-          "id": "image-size-responsive",
-          "weight": 1,
-        },
       ],
       "title": "Best Practices",
     },
@@ -933,6 +935,21 @@ Object {
           "id": "third-party-summary",
           "weight": 0,
         },
+        Object {
+          "group": "diagnostics",
+          "id": "uses-http2",
+          "weight": 0,
+        },
+        Object {
+          "group": "diagnostics",
+          "id": "uses-passive-event-listeners",
+          "weight": 0,
+        },
+        Object {
+          "group": "diagnostics",
+          "id": "no-document-write",
+          "weight": 0,
+        },
         Object {
           "id": "network-requests",
           "weight": 0,
@@ -1167,6 +1184,18 @@ Object {
       "description": "These are opportunities to to improve the experience of reading tabular or list data using assistive technology, like a screen reader.",
       "title": "Tables and lists",
     },
+    "best-practices-browser-compat": Object {
+      "title": "Browser Compatibility",
+    },
+    "best-practices-general": Object {
+      "title": "General",
+    },
+    "best-practices-trust-safety": Object {
+      "title": "Trust and Safety",
+    },
+    "best-practices-ux": Object {
+      "title": "User Experience",
+    },
     "budgets": Object {
       "description": "Performance budgets set standards for the performance of your site.",
       "title": "Budgets",
@@ -1430,6 +1459,18 @@ Object {
       "description": "These are opportunities to to improve the experience of reading tabular or list data using assistive technology, like a screen reader.",
       "title": "Tables and lists",
     },
+    "best-practices-browser-compat": Object {
+      "title": "Browser Compatibility",
+    },
+    "best-practices-general": Object {
+      "title": "General",
+    },
+    "best-practices-trust-safety": Object {
+      "title": "Trust and Safety",
+    },
+    "best-practices-ux": Object {
+      "title": "User Experience",
+    },
     "budgets": Object {
       "description": "Performance budgets set standards for the performance of your site.",
       "title": "Budgets",
diff --git a/lighthouse-cli/test/smokehouse/test-definitions/offline-local/offline-expectations.js b/lighthouse-cli/test/smokehouse/test-definitions/offline-local/offline-expectations.js
index 9c580da2f..d4ae8e077 100644
--- a/lighthouse-cli/test/smokehouse/test-definitions/offline-local/offline-expectations.js
+++ b/lighthouse-cli/test/smokehouse/test-definitions/offline-local/offline-expectations.js
@@ -20,9 +20,6 @@ module.exports = [
         'is-on-https': {
           score: 1,
         },
-        'uses-http2': {
-          score: 0,
-        },
         'external-anchors-use-rel-noopener': {
           score: 1,
         },
@@ -35,12 +32,6 @@ module.exports = [
         'render-blocking-resources': {
           score: 1,
         },
-        'no-document-write': {
-          score: 1,
-        },
-        'uses-passive-event-listeners': {
-          score: 1,
-        },
         'password-inputs-can-be-pasted-into': {
           score: 1,
         },
diff --git a/lighthouse-core/test/config/config-test.js b/lighthouse-core/test/config/config-test.js
index ebf0351ad..44bf4f125 100644
--- a/lighthouse-core/test/config/config-test.js
+++ b/lighthouse-core/test/config/config-test.js
@@ -1161,8 +1161,21 @@ describe('Config', () => {
       };
       const extendedConfig = new Config(extended);
 
+      // When gatherers have instance properties that are bind()'d, they'll not match.
+      // Gatherers in each config will still be compared via the constructor on .implementation.
+      // https://github.com/GoogleChrome/lighthouse/pull/10090#discussion_r382864319
+      function deleteInstancesForTest(config) {
+        for (const pass of config.passes) {
+          for (const gatherer of pass.gatherers) {
+            delete gatherer.instance;
+          }
+        }
+      }
+      deleteInstancesForTest(extendedConfig);
+      deleteInstancesForTest(config);
+
       assert.equal(config.passes.length, 1, 'did not filter config');
-      assert.deepStrictEqual(config, extendedConfig, 'had mutations');
+      expect(config).toEqual(extendedConfig); // ensure we didn't have mutations
     });
 
     it('should filter out other passes if passed Performance', () => {
diff --git a/lighthouse-core/test/report/report-generator-test.js b/lighthouse-core/test/report/report-generator-test.js
index 997ac9873..5f4e86dc2 100644
--- a/lighthouse-core/test/report/report-generator-test.js
+++ b/lighthouse-core/test/report/report-generator-test.js
@@ -101,7 +101,7 @@ describe('ReportGenerator', () => {
       fs.writeFileSync(path, csvOutput);
 
       const lines = csvOutput.split('\n');
-      expect(lines).toHaveLength(145);
+      expect(lines.length).toBeGreaterThan(100);
       expect(lines.slice(0, 2).join('\n')).toMatchInlineSnapshot(`
         "requestedUrl,finalUrl,category,name,title,type,score
         \\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"Performance\\",\\"first-contentful-paint\\",\\"First Contentful Paint\\",\\"numeric\\",\\"0.51\\"
diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json
index a1c2b25cd..75537ceeb 100644
--- a/lighthouse-core/test/results/sample_v2.json
+++ b/lighthouse-core/test/results/sample_v2.json
@@ -3076,7 +3076,7 @@
     },
     "no-document-write": {
       "id": "no-document-write",
-      "title": "Uses `document.write()`",
+      "title": "Avoid `document.write()`",
       "description": "For users on slow connections, external scripts dynamically injected via `document.write()` can delay page load by tens of seconds. [Learn more](https://web.dev/no-document-write).",
       "score": 0,
       "scoreDisplayMode": "binary",
@@ -3877,6 +3877,21 @@
           "weight": 0,
           "group": "diagnostics"
         },
+        {
+          "id": "uses-http2",
+          "weight": 0,
+          "group": "diagnostics"
+        },
+        {
+          "id": "uses-passive-event-listeners",
+          "weight": 0,
+          "group": "diagnostics"
+        },
+        {
+          "id": "no-document-write",
+          "weight": 0,
+          "group": "diagnostics"
+        },
         {
           "id": "network-requests",
           "weight": 0
@@ -4171,76 +4186,78 @@
       "title": "Best Practices",
       "auditRefs": [
         {
-          "id": "appcache-manifest",
-          "weight": 1
+          "id": "is-on-https",
+          "weight": 1,
+          "group": "best-practices-trust-safety"
         },
         {
-          "id": "is-on-https",
-          "weight": 1
+          "id": "external-anchors-use-rel-noopener",
+          "weight": 1,
+          "group": "best-practices-trust-safety"
         },
         {
-          "id": "uses-http2",
-          "weight": 1
+          "id": "geolocation-on-start",
+          "weight": 1,
+          "group": "best-practices-trust-safety"
         },
         {
-          "id": "uses-passive-event-listeners",
-          "weight": 1
+          "id": "notification-on-start",
+          "weight": 1,
+          "group": "best-practices-trust-safety"
         },
         {
-          "id": "no-document-write",
-          "weight": 1
+          "id": "no-vulnerable-libraries",
+          "weight": 1,
+          "group": "best-practices-trust-safety"
         },
         {
-          "id": "external-anchors-use-rel-noopener",
-          "weight": 1
+          "id": "password-inputs-can-be-pasted-into",
+          "weight": 1,
+          "group": "best-practices-ux"
         },
         {
-          "id": "geolocation-on-start",
-          "weight": 1
+          "id": "image-aspect-ratio",
+          "weight": 1,
+          "group": "best-practices-ux"
+        },
+        {
+          "id": "image-size-responsive",
+          "weight": 1,
+          "group": "best-practices-ux"
         },
         {
           "id": "doctype",
-          "weight": 1
+          "weight": 1,
+          "group": "best-practices-browser-compat"
         },
         {
           "id": "charset",
-          "weight": 1
+          "weight": 1,
+          "group": "best-practices-browser-compat"
         },
         {
-          "id": "no-vulnerable-libraries",
-          "weight": 1
+          "id": "appcache-manifest",
+          "weight": 1,
+          "group": "best-practices-general"
         },
         {
           "id": "js-libraries",
-          "weight": 0
-        },
-        {
-          "id": "notification-on-start",
-          "weight": 1
+          "weight": 0,
+          "group": "best-practices-general"
         },
         {
           "id": "deprecations",
-          "weight": 1
-        },
-        {
-          "id": "password-inputs-can-be-pasted-into",
-          "weight": 1
+          "weight": 1,
+          "group": "best-practices-general"
         },
         {
           "id": "errors-in-console",
-          "weight": 1
-        },
-        {
-          "id": "image-aspect-ratio",
-          "weight": 1
-        },
-        {
-          "id": "image-size-responsive",
-          "weight": 1
+          "weight": 1,
+          "group": "best-practices-general"
         }
       ],
       "id": "best-practices",
-      "score": 0.06
+      "score": 0.08
     },
     "seo": {
       "title": "SEO",
@@ -4480,6 +4497,18 @@
     "seo-crawl": {
       "title": "Crawling and Indexing",
       "description": "To appear in search results, crawlers need access to your app."
+    },
+    "best-practices-trust-safety": {
+      "title": "Trust and Safety"
+    },
+    "best-practices-ux": {
+      "title": "User Experience"
+    },
+    "best-practices-browser-compat": {
+      "title": "Browser Compatibility"
+    },
+    "best-practices-general": {
+      "title": "General"
     }
   },
   "timing": {
@@ -6972,6 +7001,18 @@
       "lighthouse-core/config/default-config.js | seoCrawlingGroupDescription": [
         "categoryGroups[seo-crawl].description"
       ],
+      "lighthouse-core/config/default-config.js | bestPracticesTrustSafetyGroupTitle": [
+        "categoryGroups[best-practices-trust-safety].title"
+      ],
+      "lighthouse-core/config/default-config.js | bestPracticesUXGroupTitle": [
+        "categoryGroups[best-practices-ux].title"
+      ],
+      "lighthouse-core/config/default-config.js | bestPracticesBrowserCompatGroupTitle": [
+        "categoryGroups[best-practices-browser-compat].title"
+      ],
+      "lighthouse-core/config/default-config.js | bestPracticesGeneralGroupTitle": [
+        "categoryGroups[best-practices-general].title"
+      ],
       "stack-packs/packs/wordpress.js | unused_css_rules": [
         "stackPacks[0].descriptions[unused-css-rules]"
       ],