Repository: GoogleChrome/lighthouse
Pull request #5893 (2018-08-22 17:28:29)

core(content-width): not applicable on desktop
https://twitter.com/gcmznt/status/1032188854130880512 got me thinking that since the audit is just useless in DevTools without emulation we should mark it as not applicable. The meta tag should still capture this concern on the desktop site, but honestly the whole PWA category should be taken with a grain of salt if you're not auditing with mobile (toplevel warning perhaps? or maybe the justification for category level warning 😄)

patrickhulce: Seems like this has been referenced in a few issues as a fix, anyone else wanna take a look? :)
paulirish: discussed a bit in the meeting. 

seems like 

1. we rebase this on top of emulateFormFactor. 
   1. if emulateFormFactor === desktop, then mark as not applicable.
   1. if emulateFormFactor === mobile, continue as planned
   1. if emulateFormFactor is 'none', then we look at the `HostUserAgent` artifact:
      1. if the UA is mobile (contains 'android' (_lol?_) ), continue as planned
      1. if its not mobile, mark as not applicable 

I think this captures the cases we described above. that sound right?
patrickhulce: > that sound right?

sounds great!

Patch:
diff --git a/lighthouse-core/audits/content-width.js b/lighthouse-core/audits/content-width.js
index 334206f71..7de0b62fb 100644
--- a/lighthouse-core/audits/content-width.js
+++ b/lighthouse-core/audits/content-width.js
@@ -19,23 +19,37 @@ class ContentWidth extends Audit {
       description: 'If the width of your app\'s content doesn\'t match the width ' +
           'of the viewport, your app might not be optimized for mobile screens. ' +
           '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/content-sized-correctly-for-viewport).',
-      requiredArtifacts: ['ViewportDimensions'],
+      requiredArtifacts: ['ViewportDimensions', 'HostUserAgent'],
     };
   }
 
   /**
    * @param {LH.Artifacts} artifacts
+   * @param {LH.Audit.Context} context
    * @return {LH.Audit.Product}
    */
-  static audit(artifacts) {
+  static audit(artifacts, context) {
+    const userAgent = artifacts.HostUserAgent;
     const viewportWidth = artifacts.ViewportDimensions.innerWidth;
     const windowWidth = artifacts.ViewportDimensions.outerWidth;
     const widthsMatch = viewportWidth === windowWidth;
 
-    return {
-      rawValue: widthsMatch,
-      explanation: this.createExplanation(widthsMatch, artifacts.ViewportDimensions),
-    };
+    // TODO(phulce): refactor this `isMobile` boolean to be on context
+    const isMobileHost = userAgent.includes('Android') || userAgent.includes('Mobile');
+    const isMobile = context.settings.emulatedFormFactor === 'mobile' ||
+      (context.settings.emulatedFormFactor !== 'desktop' && isMobileHost);
+
+    if (isMobile) {
+      return {
+        rawValue: widthsMatch,
+        explanation: this.createExplanation(widthsMatch, artifacts.ViewportDimensions),
+      };
+    } else {
+      return {
+        rawValue: true,
+        notApplicable: true,
+      };
+    }
   }
 
   /**
diff --git a/lighthouse-core/report/html/renderer/performance-category-renderer.js b/lighthouse-core/report/html/renderer/performance-category-renderer.js
index e9d54f409..873c0b765 100644
--- a/lighthouse-core/report/html/renderer/performance-category-renderer.js
+++ b/lighthouse-core/report/html/renderer/performance-category-renderer.js
@@ -112,7 +112,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
   /**
    * @param {LH.ReportResult.Category} category
    * @param {Object<string, LH.Result.ReportGroup>} groups
-   * @param {string=} environment 'PSI' and undefined are the only valid values
+   * @param {'PSI'=} environment 'PSI' and undefined are the only valid values
    * @return {Element}
    * @override
    */
@@ -144,9 +144,13 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
     otherMetrics.forEach(item => {
       metricsColumn2El.appendChild(this._renderMetric(item));
     });
-    const estValuesEl = this.dom.createChildOf(metricsColumn2El, 'div',
-        'lh-metrics__disclaimer lh-metrics__disclaimer');
-    estValuesEl.textContent = Util.UIStrings.varianceDisclaimer;
+
+    // 'Values are estimated and may vary' is used as the category description for PSI
+    if (environment !== 'PSI') {
+      const estValuesEl = this.dom.createChildOf(metricsColumn2El, 'div',
+          'lh-metrics__disclaimer lh-metrics__disclaimer');
+      estValuesEl.textContent = Util.UIStrings.varianceDisclaimer;
+    }
 
     metricAuditsEl.classList.add('lh-audit-group--metrics');
     element.appendChild(metricAuditsEl);


Test patch:
diff --git a/lighthouse-core/test/audits/content-width-test.js b/lighthouse-core/test/audits/content-width-test.js
index 41f8f2ed3..e4ce6e8b4 100644
--- a/lighthouse-core/test/audits/content-width-test.js
+++ b/lighthouse-core/test/audits/content-width-test.js
@@ -13,11 +13,25 @@ const assert = require('assert');
 describe('Mobile-friendly: content-width audit', () => {
   it('fails when scroll width differs from viewport width', () => {
     const result = Audit.audit({
+      HostUserAgent: 'Desktop',
       ViewportDimensions: {
         innerWidth: 100,
         outerWidth: 300,
       },
-    });
+    }, {settings: {emulatedFormFactor: 'mobile'}});
+
+    assert.equal(result.rawValue, false);
+    assert.ok(result.explanation);
+  });
+
+  it('fails when host user agent is a phone', () => {
+    const result = Audit.audit({
+      HostUserAgent: 'Mobile Android',
+      ViewportDimensions: {
+        innerWidth: 100,
+        outerWidth: 300,
+      },
+    }, {settings: {emulatedFormFactor: 'none'}});
 
     assert.equal(result.rawValue, false);
     assert.ok(result.explanation);
@@ -25,10 +39,21 @@ describe('Mobile-friendly: content-width audit', () => {
 
   it('passes when widths match', () => {
     return assert.equal(Audit.audit({
+      HostUserAgent: '',
       ViewportDimensions: {
         innerWidth: 300,
         outerWidth: 300,
       },
-    }).rawValue, true);
+    }, {settings: {emulatedFormFactor: 'mobile'}}).rawValue, true);
+  });
+
+  it('not applicable when device emulation is turned off', () => {
+    return assert.equal(Audit.audit({
+      HostUserAgent: 'Mobile Android Chrome',
+      ViewportDimensions: {
+        innerWidth: 300,
+        outerWidth: 450,
+      },
+    }, {settings: {emulatedFormFactor: 'desktop'}}).notApplicable, true);
   });
 });