Repository: GoogleChrome/lighthouse
Pull request #6848 (2018-12-19 23:50:14)

core(config): reorder categories to match new gauge order
<!-- Thank you for submitting a pull request! -->

**Summary**
Move PWA section to the end of the report to match its order on the top level score gauges.

**Related Issues/PRs**
<!-- Provide any additional information we might need to understand the pull request -->
half fix for #6837 

patrickhulce: our tests are harder to please though :)

Patch:
diff --git a/lighthouse-core/audits/uses-rel-preload.js b/lighthouse-core/audits/uses-rel-preload.js
index bcaf39191..e79680c55 100644
--- a/lighthouse-core/audits/uses-rel-preload.js
+++ b/lighthouse-core/audits/uses-rel-preload.js
@@ -20,6 +20,9 @@ const UIStrings = {
   /** Description of a Lighthouse audit that tells the user *why* they should preload important network requests. The associated network requests are started halfway through pageload (or later) but should be started at the beginning. This is displayed after a user expands the section to see more. No character length limits. '<link rel=preload>' is the html code the user would include in their page and shouldn't be translated. 'Learn More' becomes link text to additional documentation. */
   description: 'Consider using <link rel=preload> to prioritize fetching resources that are ' +
     'currently requested later in page load. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/preload).',
+  /** A warning message that is shown when the user tried to follow the advice of the audit, but it's not working as expected. Forgetting to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preload links. */
+  crossoriginWarning: 'A preload <link> was found for "{preloadURL}" but was not used ' +
+    'by the browser. Check that you are using the `crossorigin` attribute properly.',
 };
 
 const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings);
@@ -60,6 +63,25 @@ class UsesRelPreloadAudit extends Audit {
     return urls;
   }
 
+  /**
+   * Finds which URLs were attempted to be preloaded, but failed to be reused and were requested again.
+   *
+   * @param {LH.Gatherer.Simulation.GraphNode} graph
+   * @return {Set<string>}
+   */
+  static getURLsFailedToPreload(graph) {
+    /** @type {Array<LH.Artifacts.NetworkRequest>} */
+    const requests = [];
+    graph.traverse(node => node.type === 'network' && requests.push(node.record));
+
+    const preloadRequests = requests.filter(req => req.isLinkPreload);
+    const preloadURLs = new Set(preloadRequests.map(req => req.url));
+    // A failed preload attempt will manifest as a URL that was requested twice.
+    // Once with `isLinkPreload` AND again without `isLinkPreload`.
+    const failedRequests = requests.filter(req => preloadURLs.has(req.url) && !req.isLinkPreload);
+    return new Set(failedRequests.map(req => req.url));
+  }
+
   /**
    * We want to preload all first party critical requests at depth 2.
    * Third party requests can be tricky to know the URL ahead of time.
@@ -183,6 +205,14 @@ class UsesRelPreloadAudit extends Audit {
     // sort results by wastedTime DESC
     results.sort((a, b) => b.wastedMs - a.wastedMs);
 
+    /** @type {Array<string>|undefined} */
+    let warnings;
+    const failedURLs = UsesRelPreloadAudit.getURLsFailedToPreload(graph);
+    if (failedURLs.size) {
+      warnings = Array.from(failedURLs)
+        .map(preloadURL => str_(UIStrings.crossoriginWarning, {preloadURL}));
+    }
+
     /** @type {LH.Result.Audit.OpportunityDetails['headings']} */
     const headings = [
       {key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
@@ -200,6 +230,7 @@ class UsesRelPreloadAudit extends Audit {
         value: results,
       },
       details,
+      warnings,
     };
   }
 }
diff --git a/lighthouse-core/config/default-config.js b/lighthouse-core/config/default-config.js
index c8144c90c..59821c6e3 100644
--- a/lighthouse-core/config/default-config.js
+++ b/lighthouse-core/config/default-config.js
@@ -358,34 +358,6 @@ const defaultConfig = {
         {id: 'font-display', weight: 0, group: 'diagnostics'},
       ],
     },
-    'pwa': {
-      title: 'Progressive Web App',
-      description: 'These checks validate the aspects of a Progressive Web App. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist).',
-      manualDescription: 'These checks are required by the baseline ' +
-          '[PWA Checklist](https://developers.google.com/web/progressive-web-apps/checklist) but are ' +
-          'not automatically checked by Lighthouse. They do not affect your score but it\'s important that you verify them manually.',
-      auditRefs: [
-        // Fast and Reliable
-        {id: 'load-fast-enough-for-pwa', weight: 7, group: 'pwa-fast-reliable'},
-        {id: 'works-offline', weight: 5, group: 'pwa-fast-reliable'},
-        {id: 'offline-start-url', weight: 1, group: 'pwa-fast-reliable'},
-        // Installable
-        {id: 'is-on-https', weight: 2, group: 'pwa-installable'},
-        {id: 'service-worker', weight: 1, group: 'pwa-installable'},
-        {id: 'installable-manifest', weight: 2, group: 'pwa-installable'},
-        // PWA Optimized
-        {id: 'redirects-http', weight: 2, group: 'pwa-optimized'},
-        {id: 'splash-screen', weight: 1, group: 'pwa-optimized'},
-        {id: 'themed-omnibox', weight: 1, group: 'pwa-optimized'},
-        {id: 'content-width', weight: 1, group: 'pwa-optimized'},
-        {id: 'viewport', weight: 2, group: 'pwa-optimized'},
-        {id: 'without-javascript', weight: 1, group: 'pwa-optimized'},
-        // Manual audits
-        {id: 'pwa-cross-browser', weight: 0},
-        {id: 'pwa-page-transitions', weight: 0},
-        {id: 'pwa-each-page-has-url', weight: 0},
-      ],
-    },
     'accessibility': {
       title: 'Accessibility',
       description: 'These checks highlight opportunities to [improve the accessibility of your web app](https://developers.google.com/web/fundamentals/accessibility). Only a subset of accessibility issues can be automatically detected so manual testing is also encouraged.',
@@ -483,6 +455,34 @@ const defaultConfig = {
         {id: 'structured-data', weight: 0},
       ],
     },
+    'pwa': {
+      title: 'Progressive Web App',
+      description: 'These checks validate the aspects of a Progressive Web App. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist).',
+      manualDescription: 'These checks are required by the baseline ' +
+          '[PWA Checklist](https://developers.google.com/web/progressive-web-apps/checklist) but are ' +
+          'not automatically checked by Lighthouse. They do not affect your score but it\'s important that you verify them manually.',
+      auditRefs: [
+        // Fast and Reliable
+        {id: 'load-fast-enough-for-pwa', weight: 7, group: 'pwa-fast-reliable'},
+        {id: 'works-offline', weight: 5, group: 'pwa-fast-reliable'},
+        {id: 'offline-start-url', weight: 1, group: 'pwa-fast-reliable'},
+        // Installable
+        {id: 'is-on-https', weight: 2, group: 'pwa-installable'},
+        {id: 'service-worker', weight: 1, group: 'pwa-installable'},
+        {id: 'installable-manifest', weight: 2, group: 'pwa-installable'},
+        // PWA Optimized
+        {id: 'redirects-http', weight: 2, group: 'pwa-optimized'},
+        {id: 'splash-screen', weight: 1, group: 'pwa-optimized'},
+        {id: 'themed-omnibox', weight: 1, group: 'pwa-optimized'},
+        {id: 'content-width', weight: 1, group: 'pwa-optimized'},
+        {id: 'viewport', weight: 2, group: 'pwa-optimized'},
+        {id: 'without-javascript', weight: 1, group: 'pwa-optimized'},
+        // Manual audits
+        {id: 'pwa-cross-browser', weight: 0},
+        {id: 'pwa-page-transitions', weight: 0},
+        {id: 'pwa-each-page-has-url', weight: 0},
+      ],
+    },
   },
 };
 
diff --git a/lighthouse-core/lib/i18n/en-US.json b/lighthouse-core/lib/i18n/en-US.json
index c1e1a37f8..1a59b2c65 100644
--- a/lighthouse-core/lib/i18n/en-US.json
+++ b/lighthouse-core/lib/i18n/en-US.json
@@ -799,6 +799,10 @@
     "message": "Preconnect to required origins",
     "description": "Imperative title of a Lighthouse audit that tells the user to connect early to internet domains that will be used to load page resources. Origin is the correct term, however 'domain name' could be used if neccsesary. This is displayed in a list of audit titles that Lighthouse generates."
   },
+  "lighthouse-core/audits/uses-rel-preload.js | crossoriginWarning": {
+    "message": "A preload <link> was found for \"{preloadURL}\" but was not used by the browser. Check that you are using the `crossorigin` attribute properly.",
+    "description": "A warning message that is shown when the user tried to follow the advice of the audit, but it's not working as expected. Forgetting to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preload links."
+  },
   "lighthouse-core/audits/uses-rel-preload.js | description": {
     "message": "Consider using <link rel=preload> to prioritize fetching resources that are currently requested later in page load. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/preload).",
     "description": "Description of a Lighthouse audit that tells the user *why* they should preload important network requests. The associated network requests are started halfway through pageload (or later) but should be started at the beginning. This is displayed after a user expands the section to see more. No character length limits. '<link rel=preload>' is the html code the user would include in their page and shouldn't be translated. 'Learn More' becomes link text to additional documentation."


Test patch:
diff --git a/lighthouse-cli/test/fixtures/perf/level-2.js b/lighthouse-cli/test/fixtures/perf/level-2.js
index 49ddab071..76a37412b 100644
--- a/lighthouse-cli/test/fixtures/perf/level-2.js
+++ b/lighthouse-cli/test/fixtures/perf/level-2.js
@@ -6,4 +6,4 @@
 
 /* eslint-disable */
 
-document.write('<script src="level-3.js"></script>');
+document.write('<script src="/perf/level-3.js"></script>');
diff --git a/lighthouse-cli/test/fixtures/perf/preload_tester.js b/lighthouse-cli/test/fixtures/perf/preload_tester.js
index 5ac0b60e7..e81fd01d6 100644
--- a/lighthouse-cli/test/fixtures/perf/preload_tester.js
+++ b/lighthouse-cli/test/fixtures/perf/preload_tester.js
@@ -6,7 +6,8 @@
 
 /* eslint-disable */
 
-document.write('<script src="level-2.js?delay=500"></script>');
+document.write('<script src="/perf/level-2.js?delay=500"></script>');
+document.write('<script src="/perf/level-2.js?warning&delay=500"></script>');
 
 // delay our preconnect-candidates so that they're not assumed to be working already
 setTimeout(() => {
diff --git a/lighthouse-cli/test/fixtures/preload.html b/lighthouse-cli/test/fixtures/preload.html
index 2d05c12d6..c28224a08 100644
--- a/lighthouse-cli/test/fixtures/preload.html
+++ b/lighthouse-cli/test/fixtures/preload.html
@@ -1,6 +1,8 @@
 <html>
   <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
   <link rel="stylesheet" href="/perf/preload_style.css" />
+  <!-- WARN(preload): This should be no crossorigin -->
+  <link rel="preload" href="/perf/level-2.js?warning&delay=500" as="script" crossorigin="use-credentials"/>
   <!-- WARN(preconnect): This should be no crossorigin -->
   <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin="anonymous" />
   <!-- PASS(preconnect): This uses crossorigin correctly -->
diff --git a/lighthouse-cli/test/smokehouse/perf/expectations.js b/lighthouse-cli/test/smokehouse/perf/expectations.js
index 809587f28..fc8fcf297 100644
--- a/lighthouse-cli/test/smokehouse/perf/expectations.js
+++ b/lighthouse-cli/test/smokehouse/perf/expectations.js
@@ -39,6 +39,10 @@ module.exports = [
       'uses-rel-preload': {
         score: '<1',
         rawValue: '>500',
+        warnings: {
+          0: /level-2.*warning/,
+          length: 1,
+        },
         details: {
           items: {
             length: 1,
diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json
index 168f799e8..54bcb7121 100644
--- a/lighthouse-core/test/results/sample_v2.json
+++ b/lighthouse-core/test/results/sample_v2.json
@@ -2918,87 +2918,6 @@
       "id": "performance",
       "score": 0.69
     },
-    "pwa": {
-      "title": "Progressive Web App",
-      "description": "These checks validate the aspects of a Progressive Web App. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist).",
-      "manualDescription": "These checks are required by the baseline [PWA Checklist](https://developers.google.com/web/progressive-web-apps/checklist) but are not automatically checked by Lighthouse. They do not affect your score but it's important that you verify them manually.",
-      "auditRefs": [
-        {
-          "id": "load-fast-enough-for-pwa",
-          "weight": 7,
-          "group": "pwa-fast-reliable"
-        },
-        {
-          "id": "works-offline",
-          "weight": 5,
-          "group": "pwa-fast-reliable"
-        },
-        {
-          "id": "offline-start-url",
-          "weight": 1,
-          "group": "pwa-fast-reliable"
-        },
-        {
-          "id": "is-on-https",
-          "weight": 2,
-          "group": "pwa-installable"
-        },
-        {
-          "id": "service-worker",
-          "weight": 1,
-          "group": "pwa-installable"
-        },
-        {
-          "id": "installable-manifest",
-          "weight": 2,
-          "group": "pwa-installable"
-        },
-        {
-          "id": "redirects-http",
-          "weight": 2,
-          "group": "pwa-optimized"
-        },
-        {
-          "id": "splash-screen",
-          "weight": 1,
-          "group": "pwa-optimized"
-        },
-        {
-          "id": "themed-omnibox",
-          "weight": 1,
-          "group": "pwa-optimized"
-        },
-        {
-          "id": "content-width",
-          "weight": 1,
-          "group": "pwa-optimized"
-        },
-        {
-          "id": "viewport",
-          "weight": 2,
-          "group": "pwa-optimized"
-        },
-        {
-          "id": "without-javascript",
-          "weight": 1,
-          "group": "pwa-optimized"
-        },
-        {
-          "id": "pwa-cross-browser",
-          "weight": 0
-        },
-        {
-          "id": "pwa-page-transitions",
-          "weight": 0
-        },
-        {
-          "id": "pwa-each-page-has-url",
-          "weight": 0
-        }
-      ],
-      "id": "pwa",
-      "score": 0.42
-    },
     "accessibility": {
       "title": "Accessibility",
       "description": "These checks highlight opportunities to [improve the accessibility of your web app](https://developers.google.com/web/fundamentals/accessibility). Only a subset of accessibility issues can be automatically detected so manual testing is also encouraged.",
@@ -3365,6 +3284,87 @@
       ],
       "id": "seo",
       "score": null
+    },
+    "pwa": {
+      "title": "Progressive Web App",
+      "description": "These checks validate the aspects of a Progressive Web App. [Learn more](https://developers.google.com/web/progressive-web-apps/checklist).",
+      "manualDescription": "These checks are required by the baseline [PWA Checklist](https://developers.google.com/web/progressive-web-apps/checklist) but are not automatically checked by Lighthouse. They do not affect your score but it's important that you verify them manually.",
+      "auditRefs": [
+        {
+          "id": "load-fast-enough-for-pwa",
+          "weight": 7,
+          "group": "pwa-fast-reliable"
+        },
+        {
+          "id": "works-offline",
+          "weight": 5,
+          "group": "pwa-fast-reliable"
+        },
+        {
+          "id": "offline-start-url",
+          "weight": 1,
+          "group": "pwa-fast-reliable"
+        },
+        {
+          "id": "is-on-https",
+          "weight": 2,
+          "group": "pwa-installable"
+        },
+        {
+          "id": "service-worker",
+          "weight": 1,
+          "group": "pwa-installable"
+        },
+        {
+          "id": "installable-manifest",
+          "weight": 2,
+          "group": "pwa-installable"
+        },
+        {
+          "id": "redirects-http",
+          "weight": 2,
+          "group": "pwa-optimized"
+        },
+        {
+          "id": "splash-screen",
+          "weight": 1,
+          "group": "pwa-optimized"
+        },
+        {
+          "id": "themed-omnibox",
+          "weight": 1,
+          "group": "pwa-optimized"
+        },
+        {
+          "id": "content-width",
+          "weight": 1,
+          "group": "pwa-optimized"
+        },
+        {
+          "id": "viewport",
+          "weight": 2,
+          "group": "pwa-optimized"
+        },
+        {
+          "id": "without-javascript",
+          "weight": 1,
+          "group": "pwa-optimized"
+        },
+        {
+          "id": "pwa-cross-browser",
+          "weight": 0
+        },
+        {
+          "id": "pwa-page-transitions",
+          "weight": 0
+        },
+        {
+          "id": "pwa-each-page-has-url",
+          "weight": 0
+        }
+      ],
+      "id": "pwa",
+      "score": 0.42
     }
   },
   "categoryGroups": {