Repository: GoogleChrome/lighthouse
Pull request #5960 (2018-09-05 00:52:49)

core: normalize URL before checking equality
repro:

```sh
lighthouse http://paulirish.com --preset-perf -G
lighthouse http://paulirish.com --preset-perf -A

Error: Cannot run audit mode on different URL
```


Patch:
diff --git a/docs/scoring.md b/docs/scoring.md
index 5942fbf9e..f75b16534 100644
--- a/docs/scoring.md
+++ b/docs/scoring.md
@@ -58,6 +58,8 @@ Lighthouse has a whole section in the report on improving your performance score
 ### 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.
 
+*Note on https redirects*: some metrics in this category have issues with https redirects because of TLS-handshake errors. More specifically you will run into this when using the ```simplehttp2server``` npm package. Subsequent metrics will fail after the https redirects (see #1217, #5910)
+
 # 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/1Cxzhy5ecqJCucdf1M0iOzM8mIxNc7mmx107o5nj38Eo/edit#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.
diff --git a/lighthouse-core/audits/deprecations.js b/lighthouse-core/audits/deprecations.js
index 5c5484229..0df9375c9 100644
--- a/lighthouse-core/audits/deprecations.js
+++ b/lighthouse-core/audits/deprecations.js
@@ -22,7 +22,7 @@ class Deprecations extends Audit {
     return {
       id: 'deprecations',
       title: 'Avoids deprecated APIs',
-      failureTitle: 'Uses deprecated API\'s',
+      failureTitle: 'Uses deprecated APIs',
       description: 'Deprecated APIs will eventually be removed from the browser. ' +
           '[Learn more](https://www.chromestatus.com/features#deprecated).',
       requiredArtifacts: ['ChromeConsoleMessages'],
diff --git a/lighthouse-core/gather/driver.js b/lighthouse-core/gather/driver.js
index 693d4b1c9..a48327b02 100644
--- a/lighthouse-core/gather/driver.js
+++ b/lighthouse-core/gather/driver.js
@@ -115,7 +115,7 @@ class Driver {
    * @return {Promise<number>}
    */
   getBenchmarkIndex() {
-    return this.evaluateAsync(`(${pageFunctions.ultradumbBenchmark.toString()})()`);
+    return this.evaluateAsync(`(${pageFunctions.ultradumbBenchmarkString})()`);
   }
 
   /**
@@ -302,7 +302,7 @@ class Driver {
           return new __nativePromise(function (resolve) {
             return __nativePromise.resolve()
               .then(_ => ${expression})
-              .catch(${pageFunctions.wrapRuntimeEvalErrorInBrowser.toString()})
+              .catch(${pageFunctions.wrapRuntimeEvalErrorInBrowserString})
               .then(resolve);
           });
         }())`,
@@ -513,7 +513,7 @@ class Driver {
     let lastTimeout;
     let cancelled = false;
 
-    const checkForQuietExpression = `(${pageFunctions.checkTimeSinceLastLongTask.toString()})()`;
+    const checkForQuietExpression = `(${pageFunctions.checkTimeSinceLastLongTaskString})()`;
     /**
      * @param {Driver} driver
      * @param {() => void} resolve
@@ -1137,7 +1137,7 @@ class Driver {
    * @return {Promise<void>}
    */
   async registerPerformanceObserver() {
-    const scriptStr = `(${pageFunctions.registerPerformanceObserverInPage.toString()})()`;
+    const scriptStr = `(${pageFunctions.registerPerformanceObserverInPageString})()`;
     await this.evaluateScriptOnNewDocument(scriptStr);
   }
 
diff --git a/lighthouse-core/gather/gather-runner.js b/lighthouse-core/gather/gather-runner.js
index 2967a1b12..e4d77795f 100644
--- a/lighthouse-core/gather/gather-runner.js
+++ b/lighthouse-core/gather/gather-runner.js
@@ -54,8 +54,9 @@ const Driver = require('../gather/driver.js'); // eslint-disable-line no-unused-
  *     ii. all gatherers' afterPass()
  *
  * 3. Teardown
- *   A. GatherRunner.disposeDriver()
- *   B. collect all artifacts and return them
+ *   A. clearDataForOrigin
+ *   B. GatherRunner.disposeDriver()
+ *   C. collect all artifacts and return them
  *     i. collectArtifacts() from completed passes on each gatherer
  *     ii. add trace data and computed artifact methods
  */
@@ -444,6 +445,8 @@ class GatherRunner {
           firstPass = false;
         }
       }
+      const resetStorage = !options.settings.disableStorageReset;
+      if (resetStorage) await driver.clearDataForOrigin(options.requestedUrl);
       await GatherRunner.disposeDriver(driver);
       return GatherRunner.collectArtifacts(gathererResults, baseArtifacts);
     } catch (err) {
diff --git a/lighthouse-core/gather/gatherers/accessibility.js b/lighthouse-core/gather/gatherers/accessibility.js
index 8ec011298..452f0d95e 100644
--- a/lighthouse-core/gather/gatherers/accessibility.js
+++ b/lighthouse-core/gather/gatherers/accessibility.js
@@ -96,7 +96,7 @@ class Accessibility extends Gatherer {
   afterPass(passContext) {
     const driver = passContext.driver;
     const expression = `(function () {
-      ${pageFunctions.getOuterHTMLSnippet.toString()};
+      ${pageFunctions.getOuterHTMLSnippetString};
       ${axeLibSource};
       return (${runA11yChecks.toString()}());
     })()`;
diff --git a/lighthouse-core/gather/gatherers/dobetterweb/anchors-with-no-rel-noopener.js b/lighthouse-core/gather/gatherers/dobetterweb/anchors-with-no-rel-noopener.js
index d2beb9473..18ff463b9 100644
--- a/lighthouse-core/gather/gatherers/dobetterweb/anchors-with-no-rel-noopener.js
+++ b/lighthouse-core/gather/gatherers/dobetterweb/anchors-with-no-rel-noopener.js
@@ -15,8 +15,8 @@ class AnchorsWithNoRelNoopener extends Gatherer {
    */
   afterPass(passContext) {
     const expression = `(function() {
-      ${pageFunctions.getOuterHTMLSnippet.toString()};
-      ${pageFunctions.getElementsInDocument.toString()}; // define function on page
+      ${pageFunctions.getOuterHTMLSnippetString};
+      ${pageFunctions.getElementsInDocumentString}; // define function on page
       const selector = 'a[target="_blank"]:not([rel~="noopener"]):not([rel~="noreferrer"])';
       const elements = getElementsInDocument(selector);
       return elements.map(node => ({
diff --git a/lighthouse-core/gather/gatherers/dobetterweb/domstats.js b/lighthouse-core/gather/gatherers/dobetterweb/domstats.js
index 866e7b633..a949ca904 100644
--- a/lighthouse-core/gather/gatherers/dobetterweb/domstats.js
+++ b/lighthouse-core/gather/gatherers/dobetterweb/domstats.js
@@ -140,7 +140,7 @@ class DOMStats extends Gatherer {
    */
   afterPass(passContext) {
     const expression = `(function() {
-      ${pageFunctions.getOuterHTMLSnippet.toString()};
+      ${pageFunctions.getOuterHTMLSnippetString};
       ${createSelectorsLabel.toString()};
       ${elementPathInDOM.toString()};
       return (${getDOMStats.toString()}(document.documentElement));
diff --git a/lighthouse-core/gather/gatherers/dobetterweb/password-inputs-with-prevented-paste.js b/lighthouse-core/gather/gatherers/dobetterweb/password-inputs-with-prevented-paste.js
index 6b50a0e7b..f6aecee39 100644
--- a/lighthouse-core/gather/gatherers/dobetterweb/password-inputs-with-prevented-paste.js
+++ b/lighthouse-core/gather/gatherers/dobetterweb/password-inputs-with-prevented-paste.js
@@ -35,7 +35,7 @@ class PasswordInputsWithPreventedPaste extends Gatherer {
    */
   afterPass(passContext) {
     return passContext.driver.evaluateAsync(`(() => {
-      ${pageFunctions.getOuterHTMLSnippet.toString()};
+      ${pageFunctions.getOuterHTMLSnippetString};
       return (${findPasswordInputsWithPreventedPaste.toString()}());
     })()`);
   }
diff --git a/lighthouse-core/gather/gatherers/image-usage.js b/lighthouse-core/gather/gatherers/image-usage.js
index c3f89ccbf..0f9753713 100644
--- a/lighthouse-core/gather/gatherers/image-usage.js
+++ b/lighthouse-core/gather/gatherers/image-usage.js
@@ -161,7 +161,7 @@ class ImageUsage extends Gatherer {
     }, /** @type {Object<string, LH.Artifacts.SingleImageUsage['networkRecord']>} */ ({}));
 
     const expression = `(function() {
-      ${pageFunctions.getElementsInDocument.toString()}; // define function on page
+      ${pageFunctions.getElementsInDocumentString}; // define function on page
       return (${collectImageElementInfo.toString()})();
     })()`;
 
diff --git a/lighthouse-core/gather/gatherers/seo/crawlable-links.js b/lighthouse-core/gather/gatherers/seo/crawlable-links.js
index 12354fa4d..e0ead7b60 100644
--- a/lighthouse-core/gather/gatherers/seo/crawlable-links.js
+++ b/lighthouse-core/gather/gatherers/seo/crawlable-links.js
@@ -15,7 +15,7 @@ class CrawlableLinks extends Gatherer {
    */
   afterPass(passContext) {
     const expression = `(function() {
-      ${pageFunctions.getElementsInDocument.toString()}; // define function on page
+      ${pageFunctions.getElementsInDocumentString}; // define function on page
       const selector = 'a[href]:not([rel~="nofollow"])';
       const elements = getElementsInDocument(selector);
       return elements
diff --git a/lighthouse-core/gather/gatherers/seo/embedded-content.js b/lighthouse-core/gather/gatherers/seo/embedded-content.js
index da8717126..281aa1c40 100644
--- a/lighthouse-core/gather/gatherers/seo/embedded-content.js
+++ b/lighthouse-core/gather/gatherers/seo/embedded-content.js
@@ -15,7 +15,7 @@ class EmbeddedContent extends Gatherer {
    */
   afterPass(passContext) {
     const expression = `(function() {
-      ${pageFunctions.getElementsInDocument.toString()}; // define function on page
+      ${pageFunctions.getElementsInDocumentString}; // define function on page
       const selector = 'object, embed, applet';
       const elements = getElementsInDocument(selector);
       return elements
diff --git a/lighthouse-core/lib/page-functions.js b/lighthouse-core/lib/page-functions.js
index eee83cd9d..f0d05ff0b 100644
--- a/lighthouse-core/lib/page-functions.js
+++ b/lighthouse-core/lib/page-functions.js
@@ -145,10 +145,11 @@ function ultradumbBenchmark() {
 }
 
 module.exports = {
-  wrapRuntimeEvalErrorInBrowser,
-  registerPerformanceObserverInPage,
-  checkTimeSinceLastLongTask,
-  getElementsInDocument,
-  getOuterHTMLSnippet,
-  ultradumbBenchmark,
+  wrapRuntimeEvalErrorInBrowserString: wrapRuntimeEvalErrorInBrowser.toString(),
+  registerPerformanceObserverInPageString: registerPerformanceObserverInPage.toString(),
+  checkTimeSinceLastLongTaskString: checkTimeSinceLastLongTask.toString(),
+  getElementsInDocumentString: getElementsInDocument.toString(),
+  getOuterHTMLSnippetString: getOuterHTMLSnippet.toString(),
+  ultradumbBenchmark: ultradumbBenchmark,
+  ultradumbBenchmarkString: ultradumbBenchmark.toString(),
 };
diff --git a/lighthouse-core/runner.js b/lighthouse-core/runner.js
index 25facc675..37b8d7654 100644
--- a/lighthouse-core/runner.js
+++ b/lighthouse-core/runner.js
@@ -65,7 +65,7 @@ class Runner {
         if (!requestedUrl) {
           throw new Error('Cannot run audit mode on empty URL');
         }
-        if (runOpts.url && runOpts.url !== requestedUrl) {
+        if (runOpts.url && !URL.equalWithExcludedFragments(runOpts.url, requestedUrl)) {
           throw new Error('Cannot run audit mode on different URL');
         }
       } else {


Test patch:
diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json
index 230c95f8f..2d59b639d 100644
--- a/lighthouse-core/test/results/sample_v2.json
+++ b/lighthouse-core/test/results/sample_v2.json
@@ -593,7 +593,7 @@
     },
     "deprecations": {
       "id": "deprecations",
-      "title": "Uses deprecated API's",
+      "title": "Uses deprecated APIs",
       "description": "Deprecated APIs will eventually be removed from the browser. [Learn more](https://www.chromestatus.com/features#deprecated).",
       "score": 0,
       "scoreDisplayMode": "binary",
@@ -3795,4 +3795,4 @@
       ]
     }
   }
-}
\ No newline at end of file
+}
diff --git a/lighthouse-core/test/runner-test.js b/lighthouse-core/test/runner-test.js
index d29195a10..274a2067c 100644
--- a/lighthouse-core/test/runner-test.js
+++ b/lighthouse-core/test/runner-test.js
@@ -101,7 +101,7 @@ describe('Runner', () => {
 
     it('-A throws if the URL changes', async () => {
       const settings = {auditMode: artifactsPath, disableDeviceEmulation: true};
-      const opts = {url: 'https://example.com', config: generateConfig(settings), driverMock};
+      const opts = {url: 'https://differenturl.com', config: generateConfig(settings), driverMock};
       try {
         await Runner.run(null, opts);
         assert.fail('should have thrown');