Repository: GoogleChrome/lighthouse
Pull request #8971 (2019-05-16 14:59:31)

docs(readme): add performance-budgets to related projects
Was excited with the new release of budgets within lighthouse. I added a new tool that uses Docker to create an image with chrome and lighthouse that allows developers to easily set budgets.




googlebot: So there's good news and bad news.

:thumbsup: The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so.  Everything is all good there.

:confused: The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter.  We need to confirm that all authors are ok with their commits being contributed to this project.  Please have them confirm that here in the pull request.

*Note to project maintainer: This is a terminal state, meaning the `cla/google` commit status will not change from this state. It's up to you to confirm consent of all the commit author(s), set the `cla` label to `yes` (if enabled on your project), and then merge this pull request when appropriate.*

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2FGoogleChrome%2Flighthouse%2Fpull%2F8971) for more info**.

<!-- need_author_consent -->

Patch:
diff --git a/lighthouse-core/config/budget.js b/lighthouse-core/config/budget.js
index e788e8f49..0f5d1553a 100644
--- a/lighthouse-core/config/budget.js
+++ b/lighthouse-core/config/budget.js
@@ -46,6 +46,22 @@ class Budget {
     }
   }
 
+  /**
+   * Asserts that `strings` has no duplicate strings in it, throwing an error if
+   * it does. `arrayName` is included for nicer logging.
+   * @param {Array<string>} strings
+   * @param {string} arrayName
+   */
+  static assertNoDuplicateStrings(strings, arrayName) {
+    const foundStrings = new Set();
+    for (const string of strings) {
+      if (foundStrings.has(string)) {
+        throw new Error(`${arrayName} has duplicate entry of type '${string}'`);
+      }
+      foundStrings.add(string);
+    }
+  }
+
   /**
    * @param {Record<string, unknown>} resourceBudget
    * @return {LH.Budget.ResourceBudget}
@@ -94,7 +110,7 @@ class Budget {
       'first-cpu-idle',
       'interactive',
       'first-meaningful-paint',
-      'estimated-input-latency',
+      'max-potential-fid',
     ];
     // Assume metric is an allowed string, throw if not.
     if (!validTimingMetrics.includes(/** @type {LH.Budget.TimingMetric} */ (metric))) {
@@ -136,18 +152,24 @@ class Budget {
 
       if (isArrayOfUnknownObjects(resourceSizes)) {
         budget.resourceSizes = resourceSizes.map(Budget.validateResourceBudget);
+        Budget.assertNoDuplicateStrings(budget.resourceSizes.map(r => r.resourceType),
+          `budgets[${index}].resourceSizes`);
       } else if (resourceSizes !== undefined) {
         throw new Error(`Invalid resourceSizes entry in budget at index ${index}`);
       }
 
       if (isArrayOfUnknownObjects(resourceCounts)) {
         budget.resourceCounts = resourceCounts.map(Budget.validateResourceBudget);
+        Budget.assertNoDuplicateStrings(budget.resourceCounts.map(r => r.resourceType),
+          `budgets[${index}].resourceCounts`);
       } else if (resourceCounts !== undefined) {
         throw new Error(`Invalid resourceCounts entry in budget at index ${index}`);
       }
 
       if (isArrayOfUnknownObjects(timings)) {
         budget.timings = timings.map(Budget.validateTimingBudget);
+        Budget.assertNoDuplicateStrings(budget.timings.map(r => r.metric),
+          `budgets[${index}].timings`);
       } else if (timings !== undefined) {
         throw new Error(`Invalid timings entry in budget at index ${index}`);
       }
diff --git a/lighthouse-core/report/html/renderer/report-ui-features.js b/lighthouse-core/report/html/renderer/report-ui-features.js
index 2458fa5e6..bfbdc7e06 100644
--- a/lighthouse-core/report/html/renderer/report-ui-features.js
+++ b/lighthouse-core/report/html/renderer/report-ui-features.js
@@ -173,9 +173,10 @@ class ReportUIFeatures {
       });
 
     tablesWithUrls.forEach((tableEl, index) => {
-      const thirdPartyRows = this._getThirdPartyRows(tableEl, this.json.finalUrl);
-      // No 3rd parties, no checkbox!
-      if (!thirdPartyRows.size) return;
+      const urlItems = this._getUrlItems(tableEl);
+      const thirdPartyRows = this._getThirdPartyRows(tableEl, urlItems, this.json.finalUrl);
+      // If all or none of the rows are 3rd party, no checkbox!
+      if (thirdPartyRows.size === urlItems.length || !thirdPartyRows.size) return;
 
       // create input box
       const filterTemplate = this._dom.cloneTemplate('#tmpl-lh-3p-filter', this._document);
@@ -216,10 +217,10 @@ class ReportUIFeatures {
    * and returns a Map of those rows, mapping from row index to row Element.
    * @param {HTMLTableElement} el
    * @param {string} finalUrl
+   * @param {Array<HTMLElement>} urlItems
    * @return {Map<number, HTMLTableRowElement>}
    */
-  _getThirdPartyRows(el, finalUrl) {
-    const urlItems = this._dom.findAll('.lh-text__url', el);
+  _getThirdPartyRows(el, urlItems, finalUrl) {
     const finalUrlRootDomain = Util.getRootDomain(finalUrl);
 
     /** @type {Map<number, HTMLTableRowElement>} */
@@ -240,6 +241,15 @@ class ReportUIFeatures {
     return thirdPartyRows;
   }
 
+  /**
+   * From a table, finds and returns URL items.
+   * @param {HTMLTableElement} tableEl
+   * @return {Array<HTMLElement>}
+   */
+  _getUrlItems(tableEl) {
+    return this._dom.findAll('.lh-text__url', tableEl);
+  }
+
   _setupStickyHeaderElements() {
     this.topbarEl = this._dom.find('.lh-topbar', this._document);
     this.scoreScaleEl = this._dom.find('.lh-scorescale', this._document);
diff --git a/lighthouse-core/report/html/report-styles.css b/lighthouse-core/report/html/report-styles.css
index 0ba4ca75d..7e9703b35 100644
--- a/lighthouse-core/report/html/report-styles.css
+++ b/lighthouse-core/report/html/report-styles.css
@@ -1022,10 +1022,134 @@
   border: 0;
 }
 
+/* Gauge */
+
+.lh-gauge__wrapper--pass {
+  color: var(--color-pass);
+  fill: var(--color-pass);
+  stroke: var(--color-pass);
+}
+
+.lh-gauge__wrapper--average {
+  color: var(--color-average);
+  fill: var(--color-average);
+  stroke: var(--color-average);
+}
+
+.lh-gauge__wrapper--fail {
+  color: var(--color-fail);
+  fill: var(--color-fail);
+  stroke: var(--color-fail);
+}
+
+.lh-gauge {
+  stroke-linecap: round;
+  width: var(--gauge-circle-size);
+  height: var(--gauge-circle-size);
+}
+
+.lh-category .lh-gauge {
+  --gauge-circle-size: var(--gauge-circle-size-big);
+}
+
+.lh-gauge-base {
+    opacity: 0.1;
+    stroke: var(--circle-background);
+    stroke-width: var(--circle-border-width);
+}
+
+.lh-gauge-arc {
+    fill: none;
+    stroke: var(--circle-color);
+    stroke-width: var(--circle-border-width);
+    animation: load-gauge var(--transition-length) ease forwards;
+    animation-delay: 250ms;
+}
+
+.lh-gauge__svg-wrapper {
+  position: relative;
+  height: var(--gauge-circle-size);
+}
+.lh-category .lh-gauge__svg-wrapper {
+  --gauge-circle-size: var(--gauge-circle-size-big);
+}
+
+/* The plugin badge overlay */
+.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {
+  width: var(--plugin-badge-size);
+  height: var(--plugin-badge-size);
+  background-color: var(--plugin-badge-bg);
+  background-image: var(--plugin-icon-url);
+  background-repeat: no-repeat;
+  background-size: var(--plugin-icon-size);
+  background-position: 58% 50%;
+  content: "";
+  position: absolute;
+  right: -6px;
+  bottom: 0px;
+  display: block;
+  z-index: 100;
+  box-shadow: 0 0 4px rgba(0,0,0,.2);
+  border-radius: 25%;
+}
+.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {
+  width: var(--plugin-badge-size-big);
+  height: var(--plugin-badge-size-big);
+}
+
+@keyframes load-gauge {
+  from { stroke-dasharray: 0 352; }
+}
+
+.lh-gauge__percentage {
+  width: 100%;
+  height: var(--inset-size);
+  position: absolute;
+  border-radius: inherit;
+  font-family: var(--monospace-font-family);
+  font-size: var(--score-number-font-size);
+  line-height: var(--score-number-font-size);
+  text-align: center;
+  top: calc(var(--score-container-padding) + var(--gauge-circle-size) / 3);
+}
+
+.lh-category .lh-gauge__percentage {
+  --gauge-circle-size: var(--gauge-circle-size-big);
+  --score-number-font-size: var(--score-number-font-size-big);
+}
+
 .lh-gauge__wrapper {
+  position: relative;
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+  text-decoration: none;
   padding: var(--score-container-padding);
+
+  --circle-border-width: 8;
+  --transition-length: 1s;
+
+  /* Contain the layout style paint & layers during animation*/
+  contain: content;
+  will-change: opacity; /* Only using for layer promotion */
+}
+
+.lh-gauge__label {
+  font-size: var(--score-title-font-size);
+  line-height: var(--score-title-line-height);
+  margin-top: 10px;
+  text-align: center;
+  color: var(--body-text-color);
 }
 
+/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */
+.lh-category .lh-gauge__label {
+  --score-title-font-size: var(--score-title-font-size-big);
+  --score-title-line-height: var(--score-title-line-height-big);
+  margin-top: 14px;
+}
+
+
 .lh-scores-header .lh-gauge__wrapper,
 .lh-scores-header .lh-gauge--pwa__wrapper,
 .lh-sticky-header .lh-gauge__wrapper,
diff --git a/lighthouse-core/report/html/templates.html b/lighthouse-core/report/html/templates.html
index e46c5a977..cc8d7c798 100644
--- a/lighthouse-core/report/html/templates.html
+++ b/lighthouse-core/report/html/templates.html
@@ -539,132 +539,6 @@ limitations under the License.
 
 <!-- Lighthouse score gauge -->
 <template id="tmpl-lh-gauge">
-  <style>
-    .lh-gauge__wrapper--pass {
-      color: var(--color-pass);
-      fill: var(--color-pass);
-      stroke: var(--color-pass);
-    }
-
-    .lh-gauge__wrapper--average {
-      color: var(--color-average);
-      fill: var(--color-average);
-      stroke: var(--color-average);
-    }
-
-    .lh-gauge__wrapper--fail {
-      color: var(--color-fail);
-      fill: var(--color-fail);
-      stroke: var(--color-fail);
-    }
-
-    .lh-gauge {
-      stroke-linecap: round;
-      width: var(--gauge-circle-size);
-      height: var(--gauge-circle-size);
-    }
-
-    .lh-category .lh-gauge {
-      --gauge-circle-size: var(--gauge-circle-size-big);
-    }
-
-    .lh-gauge-base {
-        opacity: 0.1;
-        stroke: var(--circle-background);
-        stroke-width: var(--circle-border-width);
-    }
-
-    .lh-gauge-arc {
-        fill: none;
-        stroke: var(--circle-color);
-        stroke-width: var(--circle-border-width);
-        animation: load-gauge var(--transition-length) ease forwards;
-        animation-delay: 250ms;
-    }
-
-    .lh-gauge__svg-wrapper {
-      position: relative;
-      height: var(--gauge-circle-size);
-    }
-    .lh-category .lh-gauge__svg-wrapper {
-      --gauge-circle-size: var(--gauge-circle-size-big);
-    }
-
-    /* The plugin badge overlay */
-    .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {
-      width: var(--plugin-badge-size);
-      height: var(--plugin-badge-size);
-      background-color: var(--plugin-badge-bg);
-      background-image: var(--plugin-icon-url);
-      background-repeat: no-repeat;
-      background-size: var(--plugin-icon-size);
-      background-position: 58% 50%;
-      content: "";
-      position: absolute;
-      right: -6px;
-      bottom: 0px;
-      display: block;
-      z-index: 100;
-      box-shadow: 0 0 4px rgba(0,0,0,.2);
-      border-radius: 25%;
-    }
-    .lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {
-      width: var(--plugin-badge-size-big);
-      height: var(--plugin-badge-size-big);
-    }
-
-    @keyframes load-gauge {
-      from { stroke-dasharray: 0 352; }
-    }
-
-    .lh-gauge__percentage {
-      width: 100%;
-      height: var(--inset-size);
-      position: absolute;
-      border-radius: inherit;
-      font-family: var(--monospace-font-family);
-      font-size: var(--score-number-font-size);
-      line-height: var(--score-number-font-size);
-      text-align: center;
-      top: calc(var(--score-container-padding) + var(--gauge-circle-size) / 3);
-    }
-
-    .lh-category .lh-gauge__percentage {
-      --gauge-circle-size: var(--gauge-circle-size-big);
-      --score-number-font-size: var(--score-number-font-size-big);
-    }
-
-    .lh-gauge__wrapper {
-      position: relative;
-      display: flex;
-      align-items: center;
-      flex-direction: column;
-      text-decoration: none;
-
-      --circle-border-width: 8;
-      --transition-length: 1s;
-
-      /* Contain the layout style paint & layers during animation*/
-      contain: content;
-      will-change: opacity; /* Only using for layer promotion */
-    }
-
-    .lh-gauge__label {
-      font-size: var(--score-title-font-size);
-      line-height: var(--score-title-line-height);
-      margin-top: 10px;
-      text-align: center;
-      color: var(--body-text-color);
-    }
-
-    /* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */
-    .lh-category .lh-gauge__label {
-      --score-title-font-size: var(--score-title-font-size-big);
-      --score-title-line-height: var(--score-title-line-height-big);
-      margin-top: 14px;
-    }
-
-  </style>
   <a href="#" class="lh-gauge__wrapper">
     <!-- Wrapper exists for the ::before plugin icon. Cannot create pseudo-elements on svgs. -->
     <div class="lh-gauge__svg-wrapper">
diff --git a/readme.md b/readme.md
index 5c57b59d2..f147272b8 100644
--- a/readme.md
+++ b/readme.md
@@ -316,7 +316,7 @@ Other awesome open source projects that use Lighthouse.
 * **[lighthouse4u](https://github.com/godaddy/lighthouse4u)** - LH4U provides Google Lighthouse as a service, surfaced by both a friendly UI+API, and backed by Elastic Search for easy querying and visualization.
 * **[lighthouse-gh-reporter](https://github.com/carlesnunez/lighthouse-gh-reporter)** - Run Lighthouse in CI and report back in a comment on your pull requests
 * **[react-lighthouse-viewer](https://www.npmjs.com/package/react-lighthouse-viewer)** - Render a Lighthouse JSON report in a React Component.
-
+* **[performance-budgets](https://performance-budgets.netlify.com/)** - Easily assert Lighthouse budgets with Docker.
 ## FAQ
 
 ### How does Lighthouse work?
diff --git a/types/budget.d.ts b/types/budget.d.ts
index fa8632f1b..4c1d058b2 100644
--- a/types/budget.d.ts
+++ b/types/budget.d.ts
@@ -37,7 +37,7 @@ declare global {
       }
 
       /** Supported timing metrics. */
-      export type TimingMetric = 'first-contentful-paint' | 'first-cpu-idle' | 'interactive' | 'first-meaningful-paint' | 'estimated-input-latency';
+      export type TimingMetric = 'first-contentful-paint' | 'first-cpu-idle' | 'interactive' | 'first-meaningful-paint' | 'max-potential-fid';
 
       /** Supported values for the resourceType property of a ResourceBudget. */
       export type ResourceType = 'stylesheet' | 'image' | 'media' | 'font' | 'script' | 'document' | 'other' | 'total' | 'third-party';


Test patch:
diff --git a/lighthouse-cli/test/smokehouse/perf/perf-config.js b/lighthouse-cli/test/smokehouse/perf/perf-config.js
index 6b22341a9..f253a0502 100644
--- a/lighthouse-cli/test/smokehouse/perf/perf-config.js
+++ b/lighthouse-cli/test/smokehouse/perf/perf-config.js
@@ -41,7 +41,7 @@ const perfConfig = {
         {metric: 'first-cpu-idle', budget: 2000, tolerance: 100},
         {metric: 'interactive', budget: 2000, tolerance: 100},
         {metric: 'first-meaningful-paint', budget: 2000, tolerance: 100},
-        {metric: 'estimated-input-latency', budget: 2000, tolerance: 100},
+        {metric: 'max-potential-fid', budget: 2000, tolerance: 100},
       ],
     }],
   },
diff --git a/lighthouse-core/test/config/budget-test.js b/lighthouse-core/test/config/budget-test.js
index 19de4fb00..20b4843e8 100644
--- a/lighthouse-core/test/config/budget-test.js
+++ b/lighthouse-core/test/config/budget-test.js
@@ -146,6 +146,18 @@ describe('Budget', () => {
       assert.throws(_ => Budget.initializeBudget(budget),
         /Resource Budget has unrecognized properties: \[browser\]/);
     });
+
+    it('throws when a duplicate resourceType is specified in resourceSizes', () => {
+      budget[1].resourceSizes.push({resourceType: 'script', budget: 100});
+      assert.throws(_ => Budget.initializeBudget(budget),
+        /budgets\[1\]\.resourceSizes has duplicate entry of type 'script'/);
+    });
+
+    it('throws when a duplicate resourceType is specified in resourceCounts', () => {
+      budget[0].resourceCounts.push({resourceType: 'third-party', budget: 100});
+      assert.throws(_ => Budget.initializeBudget(budget),
+        /budgets\[0\]\.resourceCounts has duplicate entry of type 'third-party'/);
+    });
   });
 
   describe('timing budget validation', () => {
@@ -172,5 +184,11 @@ describe('Budget', () => {
       assert.throws(_ => Budget.initializeBudget(budget),
         /Timing Budget has unrecognized properties: \[device, location\]/);
     });
+
+    it('throws when a duplicate metric type is specified in timings', () => {
+      budget[0].timings.push({metric: 'interactive', budget: 1000});
+      assert.throws(_ => Budget.initializeBudget(budget),
+        /budgets\[0\]\.timings has duplicate entry of type 'interactive'/);
+    });
   });
 });
diff --git a/lighthouse-core/test/report/html/renderer/dom-test.js b/lighthouse-core/test/report/html/renderer/dom-test.js
index ea91f810f..54c623dad 100644
--- a/lighthouse-core/test/report/html/renderer/dom-test.js
+++ b/lighthouse-core/test/report/html/renderer/dom-test.js
@@ -69,8 +69,8 @@ describe('DOM', () => {
     });
 
     it('does not inject duplicate styles', () => {
-      const clone = dom.cloneTemplate('#tmpl-lh-gauge', dom.document());
-      const clone2 = dom.cloneTemplate('#tmpl-lh-gauge', dom.document());
+      const clone = dom.cloneTemplate('#tmpl-lh-snippet', dom.document());
+      const clone2 = dom.cloneTemplate('#tmpl-lh-snippet', dom.document());
       assert.ok(clone.querySelector('style'));
       assert.ok(!clone2.querySelector('style'));
     });
diff --git a/lighthouse-core/test/report/html/renderer/psi-test.js b/lighthouse-core/test/report/html/renderer/psi-test.js
index 57823bcad..c9b0b346d 100644
--- a/lighthouse-core/test/report/html/renderer/psi-test.js
+++ b/lighthouse-core/test/report/html/renderer/psi-test.js
@@ -82,7 +82,6 @@ describe('DOM', () => {
         const result = prepareLabData(sampleResultsStr, document);
         assert.ok(result.scoreGaugeEl instanceof document.defaultView.Element);
         assert.equal(result.scoreGaugeEl.querySelector('.lh-gauge__wrapper').href, '');
-        assert.ok(result.scoreGaugeEl.outerHTML.includes('<style>'), 'score gauge comes with CSS');
         assert.ok(result.scoreGaugeEl.outerHTML.includes('<svg'), 'score gauge comes with SVG');
 
         assert.ok(result.perfCategoryEl instanceof document.defaultView.Element);
diff --git a/lighthouse-core/test/report/html/renderer/report-ui-features-test.js b/lighthouse-core/test/report/html/renderer/report-ui-features-test.js
index 54a3d7852..ca825732d 100644
--- a/lighthouse-core/test/report/html/renderer/report-ui-features-test.js
+++ b/lighthouse-core/test/report/html/renderer/report-ui-features-test.js
@@ -124,6 +124,10 @@ describe('ReportUIFeatures', () => {
         const lhr = JSON.parse(JSON.stringify(sampleResults));
         lhr.requestedUrl = lhr.finalUrl = 'http://www.example.com';
         const webpAuditItemTemplate = sampleResults.audits['uses-webp-images'].details.items[0];
+        const renderBlockingAuditItemTemplate =
+          sampleResults.audits['render-blocking-resources'].details.items[0];
+        const textCompressionAuditItemTemplate =
+          sampleResults.audits['uses-text-compression'].details.items[0];
         // Interleave first/third party URLs to test restoring order.
         lhr.audits['uses-webp-images'].details.items = [
           {
@@ -140,6 +144,38 @@ describe('ReportUIFeatures', () => {
           },
         ];
 
+        // Only third party URLs to test that checkbox is hidden
+        lhr.audits['render-blocking-resources'].details.items = [
+          {
+            ...renderBlockingAuditItemTemplate,
+            url: 'http://www.cdn.com/script1.js', // Third party.
+          },
+          {
+            ...renderBlockingAuditItemTemplate,
+            url: 'http://www.google.com/script2.js', // Third party.
+          },
+          {
+            ...renderBlockingAuditItemTemplate,
+            url: 'http://www.notexample.com/script3.js', // Third party.
+          },
+        ];
+
+        // Only first party URLs to test that checkbox is hidden
+        lhr.audits['uses-text-compression'].details.items = [
+          {
+            ...textCompressionAuditItemTemplate,
+            url: 'http://www.example.com/font1.ttf', // First party.
+          },
+          {
+            ...textCompressionAuditItemTemplate,
+            url: 'http://www.example.com/font2.ttf', // First party.
+          },
+          {
+            ...textCompressionAuditItemTemplate,
+            url: 'http://www.example.com/font3.ttf', // First party.
+          },
+        ];
+
         // render a report onto the UIFeature dom
         container = render(lhr);
       });
@@ -160,7 +196,7 @@ describe('ReportUIFeatures', () => {
         expect(getUrlsInTable()).toEqual(['/img1.jpg', '/img2.jpg', '/img3.jpg']);
       });
 
-      it('adds no filter for audits that do not need them', () => {
+      it('adds no filter for audits in thirdPartyFilterAuditExclusions', () => {
         const checkboxClassName = 'lh-3p-filter-input';
 
         const yesCheckbox = dom.find(`#uses-webp-images .${checkboxClassName}`, container);
@@ -169,6 +205,20 @@ describe('ReportUIFeatures', () => {
         expect(() => dom.find(`#uses-rel-preconnect .${checkboxClassName}`, container))
           .toThrowError('query #uses-rel-preconnect .lh-3p-filter-input not found');
       });
+
+      it('adds no filter for audits with tables containing only third party resources', () => {
+        const checkboxClassName = 'lh-3p-filter-input';
+
+        expect(() => dom.find(`#render-blocking-resources .${checkboxClassName}`, container))
+          .toThrowError('query #render-blocking-resources .lh-3p-filter-input not found');
+      });
+
+      it('adds no filter for audits with tables containing only first party resources', () => {
+        const checkboxClassName = 'lh-3p-filter-input';
+
+        expect(() => dom.find(`#uses-text-compression .${checkboxClassName}`, container))
+          .toThrowError('query #uses-text-compression .lh-3p-filter-input not found');
+      });
     });
   });
 
diff --git a/lighthouse-core/test/results/sample-config.js b/lighthouse-core/test/results/sample-config.js
index 9f8144dbb..8f63818ce 100644
--- a/lighthouse-core/test/results/sample-config.js
+++ b/lighthouse-core/test/results/sample-config.js
@@ -42,7 +42,7 @@ const budgetedConfig = {
         {metric: 'first-cpu-idle', budget: 2900, tolerance: 100},
         {metric: 'interactive', budget: 2900, tolerance: 100},
         {metric: 'first-meaningful-paint', budget: 2000, tolerance: 100},
-        {metric: 'estimated-input-latency', budget: 100, tolerance: 100},
+        {metric: 'max-potential-fid', budget: 100, tolerance: 100},
       ],
     }],
   },
diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json
index 19844e8e8..89e0bd6c6 100644
--- a/lighthouse-core/test/results/sample_v2.json
+++ b/lighthouse-core/test/results/sample_v2.json
@@ -3290,7 +3290,7 @@
             "tolerance": 100
           },
           {
-            "metric": "estimated-input-latency",
+            "metric": "max-potential-fid",
             "budget": 100,
             "tolerance": 100
           }