Repository: GoogleChrome/lighthouse
Pull request #6170 (2018-10-03 21:55:12)

misc(locales): ignore all locales from devtools & extension build
<!-- Thank you for submitting a pull request! -->

**Summary**
<!-- What kind of change does this PR introduce? -->
<!-- Is this a bugfix, feature, refactoring, build related change, etc? -->
We now have 3 files we export devtools, extension and lightrider. Devtools and Extension will exclude all locale files except en-us.json. Lightrider will have all locales.

So what happend here? I created a new file called `lighthouse-lr-background.js`.

Sourcemaps can be found:
http://wardpeet-filestorage.surge.sh/lh-store/pr-6170/lighthouse-background
http://wardpeet-filestorage.surge.sh/lh-store/pr-6170/lighthouse-ext-background
http://wardpeet-filestorage.surge.sh/lh-store/pr-6170/lighthouse-lr-background

<!-- Link any documentation or information that would help understand this change -->

**Related Issues/PRs**
#5719
<!-- Provide any additional information we might need to understand the pull request -->


wardpeet: If you have a proper way of testing this please let me know. I tested the extension and no errors so far.
paulirish: @brendankenny and I thought about renaming the files here and have a proposal:

```
## src 
devtools-entry.js
extention-entry.js
lightrider-entry.js

## dest
lighthouse-dt-bundle.js
lighthouse-ext-bundle.js
lighthouse-lr-bundle.js
```

hows that feel to folks? @wardpeet let's put this filename change into the next PR. 

Patch:
diff --git a/lighthouse-core/audits/byte-efficiency/offscreen-images.js b/lighthouse-core/audits/byte-efficiency/offscreen-images.js
index fca48e3ad..0bd360ddf 100644
--- a/lighthouse-core/audits/byte-efficiency/offscreen-images.js
+++ b/lighthouse-core/audits/byte-efficiency/offscreen-images.js
@@ -165,7 +165,7 @@ class OffscreenImages extends ByteEfficiencyAudit {
    * @param {LH.Audit.Context} context
    * @return {Promise<ByteEfficiencyAudit.ByteEfficiencyProduct>}
    */
-  static audit_(artifacts, networkRecords, context) {
+  static async audit_(artifacts, networkRecords, context) {
     const images = artifacts.ImageUsage;
     const viewportDimensions = artifacts.ViewportDimensions;
     const trace = artifacts.traces[ByteEfficiencyAudit.DEFAULT_PASS];
@@ -195,29 +195,43 @@ class OffscreenImages extends ByteEfficiencyAudit {
     }, /** @type {Map<string, WasteResult>} */ (new Map()));
 
     const settings = context.settings;
-    return artifacts.requestInteractive({trace, devtoolsLog, settings}).then(interactive => {
-      const unfilteredResults = Array.from(resultsMap.values());
+
+    let items;
+    const unfilteredResults = Array.from(resultsMap.values());
+    // get the interactive time or fallback to getting the end of trace time
+    try {
+      const interactive = await artifacts.requestInteractive({trace, devtoolsLog, settings});
+
+      // use interactive to generate items
       const lanternInteractive = /** @type {LH.Artifacts.LanternMetric} */ (interactive);
       // Filter out images that were loaded after all CPU activity
-      const items = context.settings.throttlingMethod === 'simulate' ?
+      items = context.settings.throttlingMethod === 'simulate' ?
         OffscreenImages.filterLanternResults(unfilteredResults, lanternInteractive) :
         // @ts-ignore - .timestamp will exist if throttlingMethod isn't lantern
         OffscreenImages.filterObservedResults(unfilteredResults, interactive.timestamp);
+    } catch (err) {
+      // if the error is during a Lantern run, end of trace may also be inaccurate, so rethrow
+      if (context.settings.throttlingMethod === 'simulate') {
+        throw err;
+      }
+      // use end of trace as a substitute for finding interactive time
+      items = OffscreenImages.filterObservedResults(unfilteredResults,
+        await artifacts.requestTraceOfTab(trace).then(tot => tot.timestamps.traceEnd));
+    }
 
-      /** @type {LH.Result.Audit.OpportunityDetails['headings']} */
-      const headings = [
-        {key: 'url', valueType: 'thumbnail', label: ''},
-        {key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
-        {key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnSize)},
-        {key: 'wastedBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnWastedBytes)},
-      ];
-
-      return {
-        warnings,
-        items,
-        headings,
-      };
-    });
+    /** @type {LH.Result.Audit.OpportunityDetails['headings']} */
+    const headings = [
+      {key: 'url', valueType: 'thumbnail', label: ''},
+      {key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
+      {key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnSize)},
+      {key: 'wastedBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnWastedBytes)},
+    ];
+
+    return {
+      warnings,
+      items,
+      headings,
+    };
   }
 }
 
diff --git a/lighthouse-core/audits/dobetterweb/no-vulnerable-libraries.js b/lighthouse-core/audits/dobetterweb/no-vulnerable-libraries.js
index eec3543ff..cfa7fdf4b 100644
--- a/lighthouse-core/audits/dobetterweb/no-vulnerable-libraries.js
+++ b/lighthouse-core/audits/dobetterweb/no-vulnerable-libraries.js
@@ -153,7 +153,7 @@ class NoVulnerableLibrariesAudit extends Audit {
           vulnCount,
           detectedLib: {
             text: lib.name + '@' + version,
-            url: `https://snyk.io/vuln/npm:${lib.npmPkgName}?lh=${version}`,
+            url: `https://snyk.io/vuln/npm:${lib.npmPkgName}?lh=${version}&utm_source=lighthouse&utm_medium=ref&utm_campaign=audit`,
             type: 'link',
           },
         });
diff --git a/lighthouse-extension/app/src/lighthouse-ext-background.js b/lighthouse-extension/app/src/lighthouse-ext-background.js
index 8556f3be2..f4b81ca51 100644
--- a/lighthouse-extension/app/src/lighthouse-ext-background.js
+++ b/lighthouse-extension/app/src/lighthouse-ext-background.js
@@ -10,14 +10,6 @@ const background = require('./lighthouse-background');
 
 const ExtensionProtocol = require('../../../lighthouse-core/gather/connections/extension');
 const log = require('lighthouse-logger');
-const assetSaver = require('../../../lighthouse-core/lib/asset-saver.js');
-const LHError = require('../../../lighthouse-core/lib/lh-error.js');
-
-/** @type {Record<'mobile'|'desktop', LH.Config.Json>} */
-const LR_PRESETS = {
-  mobile: require('../../../lighthouse-core/config/lr-mobile-config'),
-  desktop: require('../../../lighthouse-core/config/lr-desktop-config'),
-};
 
 /** @typedef {import('../../../lighthouse-core/gather/connections/connection.js')} Connection */
 
@@ -87,56 +79,6 @@ async function runLighthouseInExtension(flags, categoryIDs) {
   await new Promise(resolve => chrome.windows.create({url: blobURL}, resolve));
 }
 
-/**
- * Run lighthouse for connection and provide similar results as in CLI.
- * @param {Connection} connection
- * @param {string} url
- * @param {LH.Flags} flags Lighthouse flags, including `output`
- * @param {{lrDevice?: 'desktop'|'mobile', categoryIDs?: Array<string>, logAssets: boolean}} lrOpts Options coming from Lightrider
- * @return {Promise<string|Array<string>|void>}
- */
-async function runLighthouseInLR(connection, url, flags, {lrDevice, categoryIDs, logAssets}) {
-  // Certain fixes need to kick-in under LR, see https://github.com/GoogleChrome/lighthouse/issues/5839
-  global.isLightRider = true;
-
-  // disableStorageReset because it causes render server hang
-  flags.disableStorageReset = true;
-  flags.logLevel = flags.logLevel || 'info';
-  const config = lrDevice === 'desktop' ? LR_PRESETS.desktop : LR_PRESETS.mobile;
-  if (categoryIDs) {
-    config.settings = config.settings || {};
-    config.settings.onlyCategories = categoryIDs;
-  }
-
-  try {
-    const results = await lighthouse(url, flags, config, connection);
-    if (!results) return;
-
-    if (logAssets) {
-      await assetSaver.logAssets(results.artifacts, results.lhr.audits);
-    }
-    return results.report;
-  } catch (err) {
-    // If an error ruined the entire lighthouse run, attempt to return a meaningful error.
-    let runtimeError;
-    if (!(err instanceof LHError) || !err.lhrRuntimeError) {
-      runtimeError = {
-        code: LHError.UNKNOWN_ERROR,
-        message: `Unknown error encountered with message '${err.message}'`,
-      };
-    } else {
-      runtimeError = {
-        code: err.code,
-        message: err.friendlyMessage ?
-            `${err.friendlyMessage} (${err.message})` :
-            err.message,
-      };
-    }
-
-    return JSON.stringify({runtimeError}, null, 2);
-  }
-}
-
 /**
  * @param {string} reportHtml
  * @return {string} Blob URL of the report (or error page) HTML
@@ -241,7 +183,6 @@ if (typeof module !== 'undefined' && module.exports) {
   // Export for importing types into popup.js, require()ing into unit tests.
   module.exports = {
     runLighthouseInExtension,
-    runLighthouseInLR,
     getDefaultCategories: background.getDefaultCategories,
     isRunning,
     listenForStatus,
@@ -255,8 +196,6 @@ if (typeof window !== 'undefined') {
   // @ts-ignore
   window.runLighthouseInExtension = runLighthouseInExtension;
   // @ts-ignore
-  window.runLighthouseInLR = runLighthouseInLR;
-  // @ts-ignore
   window.getDefaultCategories = background.getDefaultCategories;
   // @ts-ignore
   window.isRunning = isRunning;
diff --git a/lighthouse-extension/app/src/lighthouse-lr-background.js b/lighthouse-extension/app/src/lighthouse-lr-background.js
new file mode 100644
index 000000000..426d42428
--- /dev/null
+++ b/lighthouse-extension/app/src/lighthouse-lr-background.js
@@ -0,0 +1,82 @@
+/**
+ * @license Copyright 2018 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 lighthouse = require('../../../lighthouse-core/index');
+
+const assetSaver = require('../../../lighthouse-core/lib/asset-saver.js');
+const LHError = require('../../../lighthouse-core/lib/lh-error.js');
+
+/** @type {Record<'mobile'|'desktop', LH.Config.Json>} */
+const LR_PRESETS = {
+  mobile: require('../../../lighthouse-core/config/lr-mobile-config'),
+  desktop: require('../../../lighthouse-core/config/lr-desktop-config'),
+};
+
+/** @typedef {import('../../../lighthouse-core/gather/connections/connection.js')} Connection */
+
+/**
+ * Run lighthouse for connection and provide similar results as in CLI.
+ * @param {Connection} connection
+ * @param {string} url
+ * @param {LH.Flags} flags Lighthouse flags, including `output`
+ * @param {{lrDevice?: 'desktop'|'mobile', categoryIDs?: Array<string>, logAssets: boolean}} lrOpts Options coming from Lightrider
+ * @return {Promise<string|Array<string>|void>}
+ */
+async function runLighthouseInLR(connection, url, flags, {lrDevice, categoryIDs, logAssets}) {
+  // Certain fixes need to kick-in under LR, see https://github.com/GoogleChrome/lighthouse/issues/5839
+  global.isLightRider = true;
+
+  // disableStorageReset because it causes render server hang
+  flags.disableStorageReset = true;
+  flags.logLevel = flags.logLevel || 'info';
+  const config = lrDevice === 'desktop' ? LR_PRESETS.desktop : LR_PRESETS.mobile;
+  if (categoryIDs) {
+    config.settings = config.settings || {};
+    config.settings.onlyCategories = categoryIDs;
+  }
+
+  try {
+    const results = await lighthouse(url, flags, config, connection);
+    if (!results) return;
+
+    if (logAssets) {
+      await assetSaver.logAssets(results.artifacts, results.lhr.audits);
+    }
+    return results.report;
+  } catch (err) {
+    // If an error ruined the entire lighthouse run, attempt to return a meaningful error.
+    let runtimeError;
+    if (!(err instanceof LHError) || !err.lhrRuntimeError) {
+      runtimeError = {
+        code: LHError.UNKNOWN_ERROR,
+        message: `Unknown error encountered with message '${err.message}'`,
+      };
+    } else {
+      runtimeError = {
+        code: err.code,
+        message: err.friendlyMessage ?
+            `${err.friendlyMessage} (${err.message})` :
+            err.message,
+      };
+    }
+
+    return JSON.stringify({runtimeError}, null, 2);
+  }
+}
+
+if (typeof module !== 'undefined' && module.exports) {
+  // Export for importing types into popup.js, require()ing into unit tests.
+  module.exports = {
+    runLighthouseInLR,
+  };
+}
+
+// Expose on window for extension, other browser-residing consumers of file.
+if (typeof window !== 'undefined') {
+  // @ts-ignore
+  window.runLighthouseInLR = runLighthouseInLR;
+}
diff --git a/lighthouse-extension/gulpfile.js b/lighthouse-extension/gulpfile.js
index 3e71daf2e..de0249793 100644
--- a/lighthouse-extension/gulpfile.js
+++ b/lighthouse-extension/gulpfile.js
@@ -34,6 +34,13 @@ const pkg = require('../package.json');
 
 const distDir = 'dist';
 
+// list of all consumers we build for (easier to understand which file is used for which)
+const CONSUMERS = {
+  DEVTOOLS: 'lighthouse-background.js',
+  EXTENSION: 'lighthouse-ext-background.js',
+  LIGHTRIDER: 'lighthouse-lr-background.js',
+};
+
 const VERSION = pkg.version;
 const COMMIT_HASH = require('child_process')
   .execSync('git rev-parse HEAD')
@@ -50,6 +57,12 @@ const gatherers = LighthouseRunner.getGathererList()
 const computedArtifacts = LighthouseRunner.getComputedGathererList()
     .map(f => '../lighthouse-core/gather/computed/' + f.replace(/\.js$/, ''));
 
+const locales = fs.readdirSync('../lighthouse-core/lib/i18n/locales/')
+    .map(f => require.resolve(`../lighthouse-core/lib/i18n/locales/${f}`));
+
+const isDevtools = file => file.endsWith(CONSUMERS.DEVTOOLS);
+const isExtension = file => file.endsWith(CONSUMERS.EXTENSION);
+
 gulp.task('extras', () => {
   return gulp.src([
     'app/*.*',
@@ -96,7 +109,7 @@ gulp.task('chromeManifest', () => {
   const manifestOpts = {
     buildnumber: false,
     background: {
-      target: 'scripts/lighthouse-ext-background.js',
+      target: `scripts/${CONSUMERS.EXTENSION}`,
     },
   };
   return gulp.src('app/manifest.json')
@@ -114,12 +127,10 @@ function applyBrowserifyTransforms(bundle) {
 }
 
 gulp.task('browserify-lighthouse', () => {
-  return gulp.src([
-    'app/src/lighthouse-background.js',
-    'app/src/lighthouse-ext-background.js',
-  ], {read: false})
+  const consumerSources = Object.values(CONSUMERS).map(consumer => `app/src/${consumer}`);
+  return gulp.src(consumerSources, {read: false})
     .pipe(tap(file => {
-      let bundle = browserify(file.path); // , {debug: true}); // for sourcemaps
+      let bundle = browserify(file.path, {debug: true}); // for sourcemaps
       bundle = applyBrowserifyTransforms(bundle);
 
       // scripts will need some additional transforms, ignores and requires…
@@ -135,10 +146,14 @@ gulp.task('browserify-lighthouse', () => {
       bundle.ignore(require.resolve('../lighthouse-core/gather/connections/cri.js'));
 
       // Prevent the DevTools background script from getting the stringified HTML.
-      if (/lighthouse-background/.test(file.path)) {
+      if (isDevtools(file.path)) {
         bundle.ignore(require.resolve('../lighthouse-core/report/html/html-report-assets.js'));
       }
 
+      if (isDevtools(file.path) || isExtension(file.path)) {
+        bundle.ignore(locales);
+      }
+
       // Expose the audits, gatherers, and computed artifacts so they can be dynamically loaded.
       const corePath = '../lighthouse-core/';
       const driverPath = `${corePath}gather/`;
@@ -197,9 +212,8 @@ gulp.task('compilejs', () => {
     // sourceMaps: 'both'
   };
 
-  return gulp.src([
-    'dist/scripts/lighthouse-background.js',
-    'dist/scripts/lighthouse-ext-background.js'])
+  const compiledSources = Object.values(CONSUMERS).map(consumer => `dist/scripts/${consumer}`);
+  return gulp.src(compiledSources)
     .pipe(tap(file => {
       const minified = babel.transform(file.contents.toString(), opts).code;
       file.contents = new Buffer(minified);


Test patch:
diff --git a/lighthouse-core/test/audits/byte-efficiency/offscreen-images-test.js b/lighthouse-core/test/audits/byte-efficiency/offscreen-images-test.js
index 4999fa917..e101adeea 100644
--- a/lighthouse-core/test/audits/byte-efficiency/offscreen-images-test.js
+++ b/lighthouse-core/test/audits/byte-efficiency/offscreen-images-test.js
@@ -10,6 +10,7 @@ const UnusedImages =
 const NetworkNode = require('../../../lib/dependency-graph/network-node');
 const CPUNode = require('../../../lib/dependency-graph/cpu-node');
 const assert = require('assert');
+const LHError = require('../../../lib/lh-error');
 
 /* eslint-env jest */
 function generateRecord(resourceSizeInKb, startTime = 0, mimeType = 'image/png') {
@@ -50,6 +51,20 @@ function generateInteractiveFunc(desiredTimeInSeconds) {
   });
 }
 
+function generateInteractiveFuncError() {
+  return () => Promise.reject(
+    new LHError(LHError.errors.NO_TTI_NETWORK_IDLE_PERIOD)
+  );
+}
+
+function generateTraceOfTab(desiredTimeInSeconds) {
+  return () => Promise.resolve({
+    timestamps: {
+      traceEnd: desiredTimeInSeconds * 1000000,
+    },
+  });
+}
+
 describe('OffscreenImages audit', () => {
   let context;
   const DEFAULT_DIMENSIONS = {innerWidth: 1920, innerHeight: 1080};
@@ -162,6 +177,38 @@ describe('OffscreenImages audit', () => {
     });
   });
 
+  it('disregards images loaded after Trace End when interactive throws error', () => {
+    return UnusedImages.audit_({
+      ViewportDimensions: DEFAULT_DIMENSIONS,
+      ImageUsage: [
+        // offscreen to the right
+        generateImage(generateSize(200, 200), [3000, 0], generateRecord(100, 3)),
+      ],
+      traces: {},
+      devtoolsLogs: {},
+      requestInteractive: generateInteractiveFuncError(),
+      requestTraceOfTab: generateTraceOfTab(2),
+    }, [], context, [], context).then(auditResult => {
+      assert.equal(auditResult.items.length, 0);
+    });
+  });
+
+  it('finds images loaded before Trace End when TTI when interactive throws error', () => {
+    return UnusedImages.audit_({
+      ViewportDimensions: DEFAULT_DIMENSIONS,
+      ImageUsage: [
+        // offscreen to the right
+        generateImage(generateSize(100, 100), [0, 2000], generateRecord(100)),
+      ],
+      traces: {},
+      devtoolsLogs: {},
+      requestInteractive: generateInteractiveFuncError(),
+      requestTraceOfTab: generateTraceOfTab(2),
+    }, [], context, [], context).then(auditResult => {
+      assert.equal(auditResult.items.length, 1);
+    });
+  });
+
   it('disregards images loaded after last long task (Lantern)', () => {
     context = {settings: {throttlingMethod: 'simulate'}};
     const recordA = {url: 'a', resourceSize: 100 * 1024, requestId: 'a'};
@@ -190,4 +237,75 @@ describe('OffscreenImages audit', () => {
       assert.equal(auditResult.items[0].url, 'a');
     });
   });
+
+  it('finds images loaded before last long task (Lantern)', () => {
+    context = {settings: {throttlingMethod: 'simulate'}};
+    const recordA = {url: 'a', resourceSize: 100 * 1024, requestId: 'a'};
+    const recordB = {url: 'b', resourceSize: 100 * 1024, requestId: 'b'};
+
+    const networkA = new NetworkNode(recordA);
+    const networkB = new NetworkNode(recordB);
+    const cpu = new CPUNode({}, []);
+    const timings = new Map([
+      [networkA, {startTime: 1000}],
+      [networkB, {startTime: 1500}],
+      [cpu, {startTime: 1975, endTime: 2025, duration: 50}],
+    ]);
+
+    return UnusedImages.audit_({
+      ViewportDimensions: DEFAULT_DIMENSIONS,
+      ImageUsage: [
+        generateImage(generateSize(0, 0), [0, 0], recordA, recordA.url),
+        generateImage(generateSize(200, 200), [3000, 0], recordB, recordB.url),
+      ],
+      traces: {},
+      devtoolsLogs: {},
+      requestInteractive: async () => ({pessimisticEstimate: {nodeTimings: timings}}),
+      requestTraceOfTab: generateTraceOfTab(2),
+    }, [], context, [], context).then(auditResult => {
+      assert.equal(auditResult.items.length, 2);
+      assert.equal(auditResult.items[0].url, 'a');
+      assert.equal(auditResult.items[1].url, 'b');
+    });
+  });
+
+  it('rethrow error when interactive throws error in Lantern', async () => {
+    context = {settings: {throttlingMethod: 'simulate'}};
+    try {
+      await UnusedImages.audit_({
+        ViewportDimensions: DEFAULT_DIMENSIONS,
+        ImageUsage: [
+          generateImage(generateSize(0, 0), [0, 0], generateRecord(100, 3), 'a'),
+          generateImage(generateSize(200, 200), [3000, 0], generateRecord(100, 4), 'b'),
+        ],
+        traces: {},
+        devtoolsLogs: {},
+        requestInteractive: generateInteractiveFuncError(),
+        requestTraceOfTab: generateTraceOfTab(2),
+      }, [], context, [], context);
+    } catch (err) {
+      return;
+    }
+    assert.ok(false);
+  });
+
+  it('finds images loaded before Trace End when interactive throws error (Lantern)', async () => {
+    context = {settings: {throttlingMethod: 'simulate'}};
+    try {
+      await UnusedImages.audit_({
+        ViewportDimensions: DEFAULT_DIMENSIONS,
+        ImageUsage: [
+          generateImage(generateSize(0, 0), [0, 0], generateRecord(100, 1), 'a'),
+          generateImage(generateSize(200, 200), [3000, 0], generateRecord(100, 4), 'b'),
+        ],
+        traces: {},
+        devtoolsLogs: {},
+        requestInteractive: generateInteractiveFuncError(),
+        requestTraceOfTab: generateTraceOfTab(2),
+      }, [], context, [], context);
+    } catch (err) {
+      return;
+    }
+    assert.ok(false);
+  });
 });
diff --git a/lighthouse-core/test/audits/dobetterweb/no-vulnerable-libraries-test.js b/lighthouse-core/test/audits/dobetterweb/no-vulnerable-libraries-test.js
index c225d7272..6c9151c61 100644
--- a/lighthouse-core/test/audits/dobetterweb/no-vulnerable-libraries-test.js
+++ b/lighthouse-core/test/audits/dobetterweb/no-vulnerable-libraries-test.js
@@ -40,7 +40,7 @@ describe('Avoids front-end JavaScript libraries with known vulnerabilities', ()
     assert.equal(auditResult.details.items[0].highestSeverity, 'High');
     assert.equal(auditResult.details.items[0].detectedLib.type, 'link');
     assert.equal(auditResult.details.items[0].detectedLib.text, 'angular@1.1.4');
-    assert.equal(auditResult.details.items[0].detectedLib.url, 'https://snyk.io/vuln/npm:angular?lh=1.1.4');
+    assert.equal(auditResult.details.items[0].detectedLib.url, 'https://snyk.io/vuln/npm:angular?lh=1.1.4&utm_source=lighthouse&utm_medium=ref&utm_campaign=audit');
   });
 
   it('handles ill-specified versions', () => {
diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json
index 7451b200a..9c93ce33b 100644
--- a/lighthouse-core/test/results/sample_v2.json
+++ b/lighthouse-core/test/results/sample_v2.json
@@ -2376,7 +2376,7 @@
             "vulnCount": 1,
             "detectedLib": {
               "text": "jQuery@2.1.1",
-              "url": "https://snyk.io/vuln/npm:jquery?lh=2.1.1",
+              "url": "https://snyk.io/vuln/npm:jquery?lh=2.1.1&utm_source=lighthouse&utm_medium=ref&utm_campaign=audit",
               "type": "link"
             }
           }
diff --git a/lighthouse-extension/test/app/src/lighthouse-ext-background-test.js b/lighthouse-extension/test/app/src/lighthouse-lr-background-test.js
similarity index 95%
rename from lighthouse-extension/test/app/src/lighthouse-ext-background-test.js
rename to lighthouse-extension/test/app/src/lighthouse-lr-background-test.js
index c66858d8e..757224c31 100644
--- a/lighthouse-extension/test/app/src/lighthouse-ext-background-test.js
+++ b/lighthouse-extension/test/app/src/lighthouse-lr-background-test.js
@@ -6,12 +6,12 @@
 'use strict';
 
 const assert = require('assert');
-const lhBackground = require('../../../app/src/lighthouse-ext-background.js');
+const lhBackground = require('../../../app/src/lighthouse-lr-background.js');
 const LHError = require('../../../../lighthouse-core/lib/lh-error.js');
 
 /* eslint-env mocha */
 
-describe('lighthouse-ext-background', () => {
+describe('lighthouse-lr-background', () => {
   describe('#runLighthouseInLR', () => {
     it('returns a runtimeError LHR when lighthouse throws a runtimeError', async () => {
       const connectionError = new LHError(LHError.errors.FAILED_DOCUMENT_REQUEST);