Repository: GoogleChrome/lighthouse
Pull request #7492 (2019-03-14 02:25:29)

misc: fix typo in comment


Patch:
diff --git a/build/dt-report-generator-bundle.js b/build/dt-report-generator-bundle.js
new file mode 100644
index 000000000..0dd028b4f
--- /dev/null
+++ b/build/dt-report-generator-bundle.js
@@ -0,0 +1,19 @@
+/**
+ * @license Copyright 2019 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+ */
+'use strict';
+
+const browserify = require('browserify');
+const fs = require('fs');
+
+const distDir = __dirname + '/../dist';
+const outFile = `${distDir}/report-generator.js`;
+const generatorFilename = `./lighthouse-core/report/report-generator.js`;
+browserify(generatorFilename, {standalone: 'ReportGenerator'})
+  .transform('brfs')
+  .bundle((err, src) => {
+    if (err) throw err;
+    fs.writeFileSync(outFile, src.toString());
+  });
diff --git a/lighthouse-core/audits/dobetterweb/uses-http2.js b/lighthouse-core/audits/dobetterweb/uses-http2.js
index 998167b6f..6ca132cc7 100644
--- a/lighthouse-core/audits/dobetterweb/uses-http2.js
+++ b/lighthouse-core/audits/dobetterweb/uses-http2.js
@@ -44,6 +44,9 @@ class UsesHTTP2Audit extends Audit {
       const seenURLs = new Set();
       // Filter requests that are on the same host as the page and not over h2.
       const resources = networkRecords.filter(record => {
+        // check if record is not served through the service worker, servicer worker uses http/1.1 as a protocol
+        // these can generate false positives (bug: https://github.com/GoogleChrome/lighthouse/issues/7158)
+        if (record.fetchedViaServiceWorker) return false;
         // test the protocol first to avoid (potentially) expensive URL parsing
         const isOldHttp = /HTTP\/[01][.\d]?/i.test(record.protocol);
         if (!isOldHttp) return false;
diff --git a/lighthouse-core/audits/image-aspect-ratio.js b/lighthouse-core/audits/image-aspect-ratio.js
index a3fc6bdec..d8764278d 100644
--- a/lighthouse-core/audits/image-aspect-ratio.js
+++ b/lighthouse-core/audits/image-aspect-ratio.js
@@ -72,10 +72,13 @@ class ImageAspectRatio extends Audit {
     /** @type {Array<{url: string, displayedAspectRatio: string, actualAspectRatio: string, doRatiosMatch: boolean}>} */
     const results = [];
     images.filter(image => {
+      // - filter out css background images since we don't have a reliable way to tell if it's a
+      //   sprite sheet, repeated for effect, etc
       // - filter out images that don't have following properties:
       //   networkRecord, width, height, images that use `object-fit`: `cover` or `contain`
       // - filter all svgs as they have no natural dimensions to audit
-      return image.mimeType &&
+      return !image.isCss &&
+        image.mimeType &&
         image.mimeType !== 'image/svg+xml' &&
         image.naturalHeight > 5 &&
         image.naturalWidth > 5 &&
diff --git a/lighthouse-core/gather/gather-runner.js b/lighthouse-core/gather/gather-runner.js
index 6237ff706..caf31fe9c 100644
--- a/lighthouse-core/gather/gather-runner.js
+++ b/lighthouse-core/gather/gather-runner.js
@@ -128,7 +128,7 @@ class GatherRunner {
     } catch (err) {
       // Ignore disconnecting error if browser was already closed.
       // See https://github.com/GoogleChrome/lighthouse/issues/1583
-      if (!(/close\/.*status: 500$/.test(err.message))) {
+      if (!(/close\/.*status: (500|404)$/.test(err.message))) {
         log.error('GatherRunner disconnect', err.message);
       }
     }
diff --git a/lighthouse-core/lib/network-request.js b/lighthouse-core/lib/network-request.js
index 5ed1acea4..687924e0b 100644
--- a/lighthouse-core/lib/network-request.js
+++ b/lighthouse-core/lib/network-request.js
@@ -302,7 +302,7 @@ module.exports = class NetworkRequest {
    * The total length of the encoded data is spread out among multiple events. The sum of the
    * values in onResponseReceived and all the onDataReceived events typically equals the value
    * seen on the onLoadingFinished event. In <1% of cases we see the values differ. As we process
-   * onResonseReceived and onDataReceived we accumulate the total encodedDataLength. When we
+   * onResponseReceived and onDataReceived we accumulate the total encodedDataLength. When we
    * process onLoadingFinished, we override the accumulated total. We do this so that if the
    * request is aborted or fails, we still get a value via the accumulation.
    *
diff --git a/lighthouse-core/report/html/renderer/dom.js b/lighthouse-core/report/html/renderer/dom.js
index 4d178fcdc..dee3fa981 100644
--- a/lighthouse-core/report/html/renderer/dom.js
+++ b/lighthouse-core/report/html/renderer/dom.js
@@ -27,6 +27,8 @@ class DOM {
   constructor(document) {
     /** @type {Document} */
     this._document = document;
+    /** @type {string} */
+    this._lighthouseChannel = 'unknown';
   }
 
   /**
@@ -125,11 +127,19 @@ class DOM {
 
       // Append link if there are any.
       if (linkText && linkHref) {
+        const url = new URL(linkHref);
+
+        const DEVELOPERS_GOOGLE_ORIGIN = 'https://developers.google.com';
+        if (url.origin === DEVELOPERS_GOOGLE_ORIGIN) {
+          url.searchParams.set('utm_source', 'lighthouse');
+          url.searchParams.set('utm_medium', this._lighthouseChannel);
+        }
+
         const a = this.createElement('a');
         a.rel = 'noopener';
         a.target = '_blank';
         a.textContent = linkText;
-        a.href = (new URL(linkHref)).href;
+        a.href = url.href;
         element.appendChild(a);
       }
     }
@@ -159,6 +169,14 @@ class DOM {
     return element;
   }
 
+  /**
+   * The channel to use for UTM data when rendering links to the documentation.
+   * @param {string} lighthouseChannel
+   */
+  setLighthouseChannel(lighthouseChannel) {
+    this._lighthouseChannel = lighthouseChannel;
+  }
+
   /**
    * @return {Document}
    */
diff --git a/lighthouse-core/report/html/renderer/report-renderer.js b/lighthouse-core/report/html/renderer/report-renderer.js
index 325c27dc5..7a997ee26 100644
--- a/lighthouse-core/report/html/renderer/report-renderer.js
+++ b/lighthouse-core/report/html/renderer/report-renderer.js
@@ -47,6 +47,8 @@ class ReportRenderer {
     // Mutate the UIStrings if necessary (while saving originals)
     const originalUIStrings = JSON.parse(JSON.stringify(Util.UIStrings));
 
+    this._dom.setLighthouseChannel(result.configSettings.channel || 'unknown');
+
     const report = Util.prepareReportResult(result);
 
     container.textContent = ''; // Remove previous report.
diff --git a/lighthouse-core/report/html/report-styles.css b/lighthouse-core/report/html/report-styles.css
index 7915e7bd0..0c579479e 100644
--- a/lighthouse-core/report/html/report-styles.css
+++ b/lighthouse-core/report/html/report-styles.css
@@ -801,7 +801,9 @@
 }
 
 .lh-scores-header .lh-gauge--pwa__wrapper {
-  border-left: 1px solid var(--report-secondary-border-color)
+  border-left: 1px solid var(--report-secondary-border-color);
+  /* Can remove when this bug is resolved: https://bugs.chromium.org/p/chromium/issues/detail?id=942097 */
+  will-change: transform;
 }
 
 .lh-scorescale {
diff --git a/lighthouse-core/report/report-generator.js b/lighthouse-core/report/report-generator.js
index 09d653a30..61561c6d2 100644
--- a/lighthouse-core/report/report-generator.js
+++ b/lighthouse-core/report/report-generator.js
@@ -8,6 +8,10 @@
 const htmlReportAssets = require('./html/html-report-assets');
 
 class ReportGenerator {
+  static getAssets() {
+    return htmlReportAssets;
+  }
+
   /**
    * Replaces all the specified strings in source without serial replacements.
    * @param {string} source
diff --git a/lighthouse-core/scripts/roll-to-devtools.sh b/lighthouse-core/scripts/roll-to-devtools.sh
index 78e879f96..b33714397 100755
--- a/lighthouse-core/scripts/roll-to-devtools.sh
+++ b/lighthouse-core/scripts/roll-to-devtools.sh
@@ -37,9 +37,12 @@ lh_bg_js="dist/lighthouse-dt-bundle.js"
 lh_worker_dir="$frontend_dir/audits2_worker/lighthouse"
 
 # copy report files
-cp -pPR $report_dir/{report-styles.css,templates.html,renderer} "$fe_lh_dir"
+cp -pPR $report_dir/renderer "$fe_lh_dir"
 echo -e "\033[32m ✓\033[39m Report renderer files copied."
 
 # copy lighthouse-dt-bundle (potentially stale)
 cp -pPR "$lh_bg_js" "$lh_worker_dir/lighthouse-dt-bundle.js"
 echo -e "\033[96m ✓\033[39m (Potentially stale) lighthouse-dt-bundle copied."
+
+# copy report generator
+cp dist/report-generator.js $fe_lh_dir
diff --git a/package.json b/package.json
index 3a686223d..0ac570027 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
     "build-all:task": "yarn build-extension & yarn build-devtools & yarn build-lr & yarn build-viewer & wait",
     "build-all:task:windows": "yarn build-extension && yarn build-devtools && yarn build-lr && yarn build-viewer",
     "build-extension": "node ./build/build-extension.js",
-    "build-devtools": "node ./build/build-bundle.js clients/devtools-entry.js dist/lighthouse-dt-bundle.js",
+    "build-devtools": "node ./build/build-bundle.js clients/devtools-entry.js dist/lighthouse-dt-bundle.js && node ./build/dt-report-generator-bundle.js",
     "build-lr": "node ./build/build-bundle.js clients/lightrider-entry.js dist/lighthouse-lr-bundle.js",
     "build-viewer": "node ./build/build-viewer.js",
     "clean": "rimraf dist proto/scripts/*.json proto/scripts/*_pb2.* proto/scripts/*_pb.* proto/scripts/__pycache__ proto/scripts/*.pyc *.report.html *.report.dom.html *.report.json *.devtoolslog.json *.trace.json || true",
diff --git a/third-party/snyk/snapshot.json b/third-party/snyk/snapshot.json
index 5c67d2de5..19702dea0 100644
--- a/third-party/snyk/snapshot.json
+++ b/third-party/snyk/snapshot.json
@@ -57,7 +57,7 @@
       {"id":"npm:highcharts:20180225","severity":"high","semver":{"vulnerable":["<6.1.0"]}}
     ],
     "jquery":[
-      {"id":"npm:jquery:20160529","severity":"low","semver":{"vulnerable":["=3.0.0-rc.1"]}},
+      {"id":"npm:jquery:20160529","severity":"low","semver":{"vulnerable":["=3.0.0-rc1"]}},
       {"id":"npm:jquery:20150627","severity":"medium","semver":{"vulnerable":["<1.12.2",">=1.12.3 <2.2.2",">=2.2.3 <3.0.0"]}},
       {"id":"npm:jquery:20140902","severity":"medium","semver":{"vulnerable":[">=1.4.2 <1.6.2"]}},
       {"id":"npm:jquery:20120206","severity":"medium","semver":{"vulnerable":["<1.9.0 >=1.7.1"]}},


Test patch:
diff --git a/lighthouse-core/test/audits/dobetterweb/uses-http2-test.js b/lighthouse-core/test/audits/dobetterweb/uses-http2-test.js
index c43793ceb..5e8f8d20f 100644
--- a/lighthouse-core/test/audits/dobetterweb/uses-http2-test.js
+++ b/lighthouse-core/test/audits/dobetterweb/uses-http2-test.js
@@ -26,26 +26,29 @@ describe('Resources are fetched over http/2', () => {
   }
 
   it('fails when some resources were requested via http/1.x', () => {
-    return UsesHTTP2Audit.audit(
-      getArtifacts(networkRecords, URL), {computedCache: new Map()}
-    ).then(auditResult => {
-      assert.equal(auditResult.rawValue, false);
-      assert.ok(auditResult.displayValue.match('3 requests not'));
-      assert.equal(auditResult.details.items.length, 3);
-      assert.equal(auditResult.details.items[0].url, 'https://webtide.com/wp-content/plugins/wp-pagenavi/pagenavi-css.css?ver=2.70');
-      const headers = auditResult.details.headings;
-      assert.equal(headers[0].text, 'URL', 'table headings are correct and in order');
-      assert.equal(headers[1].text, 'Protocol', 'table headings are correct and in order');
-    });
+    return UsesHTTP2Audit.audit(getArtifacts(networkRecords, URL), {computedCache: new Map()}).then(
+      auditResult => {
+        assert.equal(auditResult.rawValue, false);
+        assert.ok(auditResult.displayValue.match('3 requests not'));
+        assert.equal(auditResult.details.items.length, 3);
+        assert.equal(
+          auditResult.details.items[0].url,
+          'https://webtide.com/wp-content/plugins/wp-pagenavi/pagenavi-css.css?ver=2.70'
+        );
+        const headers = auditResult.details.headings;
+        assert.equal(headers[0].text, 'URL', 'table headings are correct and in order');
+        assert.equal(headers[1].text, 'Protocol', 'table headings are correct and in order');
+      }
+    );
   });
 
   it('displayValue is correct when only one resource fails', () => {
     const entryWithHTTP1 = networkRecords.slice(1, 2);
-    return UsesHTTP2Audit.audit(
-      getArtifacts(entryWithHTTP1, URL), {computedCache: new Map()}
-    ).then(auditResult => {
-      assert.ok(auditResult.displayValue.match('1 request not'));
-    });
+    return UsesHTTP2Audit.audit(getArtifacts(entryWithHTTP1, URL), {computedCache: new Map()}).then(
+      auditResult => {
+        assert.ok(auditResult.displayValue.match('1 request not'));
+      }
+    );
   });
 
   it('passes when all resources were requested via http/2', () => {
@@ -54,11 +57,34 @@ describe('Resources are fetched over http/2', () => {
       record.protocol = 'h2';
     });
 
-    return UsesHTTP2Audit.audit(
-      getArtifacts(h2Records, URL), {computedCache: new Map()}
-    ).then(auditResult => {
-      assert.equal(auditResult.rawValue, true);
-      assert.ok(auditResult.displayValue === '');
+    return UsesHTTP2Audit.audit(getArtifacts(h2Records, URL), {computedCache: new Map()}).then(
+      auditResult => {
+        assert.equal(auditResult.rawValue, true);
+        assert.ok(auditResult.displayValue === '');
+      }
+    );
+  });
+
+  it('results are correct when some requests are handled by service worker', () => {
+    const clonedNetworkRecords = JSON.parse(JSON.stringify(networkRecords));
+    clonedNetworkRecords.forEach(record => {
+      // convert http 1.1 to service worker requests
+      if (record.protocol === 'http/1.1') {
+        record.fetchedViaServiceWorker = true;
+      }
+    });
+
+    return UsesHTTP2Audit.audit(getArtifacts(clonedNetworkRecords, URL), {
+      computedCache: new Map(),
+    }).then(auditResult => {
+      assert.equal(auditResult.rawValue, false);
+      assert.ok(auditResult.displayValue.match('1 request not'));
+      // Protocol is http/1.0 which we don't mark as fetched fetchedViaServiceWorker on line 73.
+      assert.equal(
+        auditResult.details.items[0].url,
+        'https://webtide.com/wp-content/themes/clean-retina-pro/library/js/tinynav.js?ver=4.5.4'
+      );
+      assert.equal(auditResult.details.items[0].protocol, 'http/1.0');
     });
   });
 });
diff --git a/lighthouse-core/test/audits/image-aspect-ratio-test.js b/lighthouse-core/test/audits/image-aspect-ratio-test.js
index 6b3902db4..8717a371f 100644
--- a/lighthouse-core/test/audits/image-aspect-ratio-test.js
+++ b/lighthouse-core/test/audits/image-aspect-ratio-test.js
@@ -39,6 +39,15 @@ describe('Images: aspect-ratio audit', () => {
     });
   }
 
+  testImage('is a css image', {
+    rawValue: true,
+    clientSize: [1000, 20],
+    naturalSize: [5, 5],
+    props: {
+      isCss: true,
+    },
+  });
+
   testImage('is much larger than natural aspect ratio', {
     rawValue: false,
     clientSize: [800, 500],
diff --git a/lighthouse-core/test/network-records-to-devtools-log.js b/lighthouse-core/test/network-records-to-devtools-log.js
index 0eb6e9e1c..50c380345 100644
--- a/lighthouse-core/test/network-records-to-devtools-log.js
+++ b/lighthouse-core/test/network-records-to-devtools-log.js
@@ -100,7 +100,7 @@ function getResponseReceivedEvent(networkRecord, index) {
         connectionReused: networkRecord.connectionReused || false,
         connectionId: networkRecord.connectionId || 140,
         fromDiskCache: networkRecord.fromDiskCache || undefined,
-        fromServiceWorker: networkRecord.fromServiceWorker || undefined,
+        fromServiceWorker: networkRecord.fetchedViaServiceWorker || undefined,
         encodedDataLength: networkRecord.transferSize || 0,
         timing,
         protocol: networkRecord.protocol || 'http/1.1',
diff --git a/lighthouse-core/test/report/html/renderer/dom-test.js b/lighthouse-core/test/report/html/renderer/dom-test.js
index 96bda5074..ea91f810f 100644
--- a/lighthouse-core/test/report/html/renderer/dom-test.js
+++ b/lighthouse-core/test/report/html/renderer/dom-test.js
@@ -23,6 +23,7 @@ describe('DOM', () => {
     global.URL = URL;
     const {document} = new jsdom.JSDOM(TEMPLATE_FILE).window;
     dom = new DOM(document);
+    dom.setLighthouseChannel('someChannel');
   });
 
   afterAll(() => {
@@ -115,6 +116,20 @@ describe('DOM', () => {
       assert.equal(result.innerHTML, 'Ensuring `&lt;td&gt;` cells using the `[headers]` are ' +
           'good. <a rel="noopener" target="_blank" href="https://dequeuniversity.com/rules/axe/3.1/td-headers-attr">Learn more</a>.');
     });
+
+    it('appends utm params to the URLs with https://developers.google.com origin', () => {
+      const text = '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/description).';
+
+      const result = dom.convertMarkdownLinkSnippets(text);
+      assert.equal(result.innerHTML, '<a rel="noopener" target="_blank" href="https://developers.google.com/web/tools/lighthouse/audits/description?utm_source=lighthouse&amp;utm_medium=someChannel">Learn more</a>.');
+    });
+
+    it('doesn\'t append utm params to non https://developers.google.com origins', () => {
+      const text = '[Learn more](https://example.com/info).';
+
+      const result = dom.convertMarkdownLinkSnippets(text);
+      assert.equal(result.innerHTML, '<a rel="noopener" target="_blank" href="https://example.com/info">Learn more</a>.');
+    });
   });
 
   describe('convertMarkdownCodeSnippets', () => {
diff --git a/lighthouse-core/test/report/html/renderer/report-renderer-test.js b/lighthouse-core/test/report/html/renderer/report-renderer-test.js
index 478d8dd81..f8362c66c 100644
--- a/lighthouse-core/test/report/html/renderer/report-renderer-test.js
+++ b/lighthouse-core/test/report/html/renderer/report-renderer-test.js
@@ -199,6 +199,25 @@ describe('ReportRenderer', () => {
     assert.ok(output.querySelector('.score100'), 'has fireworks treatment');
   });
 
+  it('should add LHR channel to doc link parameters', () => {
+    const lhrChannel = sampleResults.configSettings.channel;
+    // Make sure we have a channel in the LHR.
+    assert.ok(lhrChannel.length > 2);
+
+    const container = renderer._dom._document.body;
+    const output = renderer.renderReport(sampleResults, container);
+
+    const utmChannels = [...output.querySelectorAll('a[href*="utm_source=lighthouse"')]
+      .map(a => new URL(a.href))
+      .filter(url => url.origin === 'https://developers.google.com')
+      .map(url => url.searchParams.get('utm_medium'));
+
+    assert.ok(utmChannels.length > 20);
+    utmChannels.forEach(anchorChannel => {
+      assert.strictEqual(anchorChannel, lhrChannel);
+    });
+  });
+
   it('renders `not_applicable` audits as `notApplicable`', () => {
     const clonedSampleResult = JSON.parse(JSON.stringify(sampleResultsOrig));