Repository: GoogleChrome/lighthouse
Pull request #9226 (2019-06-17 22:42:38)

docs: update understanding-results.md
inspired by #9225.. here's a few more.

Didn't mention these properties: `lhr.environment`, `lhr.stackPacks`, `lhr.i18n`... but otherwise I believe the rest is up to date.


Patch:
diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md
index ea0f5dc98..098af3840 100644
--- a/.github/ISSUE_TEMPLATE/Bug_report.md
+++ b/.github/ISSUE_TEMPLATE/Bug_report.md
@@ -10,6 +10,8 @@ about: Report something working incorrectly
 
 #### Provide the steps to reproduce
 1. Run LH on <affected url>
+  
+<!-- If your page is only local, or is liable to change, consider uploading a repro so that we can more easily debug the problem. Some services that will help are: https://jsbin.com/, https://surge.sh/ -->
 
 #### What is the current behavior?
 
diff --git a/docs/understanding-results.md b/docs/understanding-results.md
index c753e8e1d..587f83e5d 100644
--- a/docs/understanding-results.md
+++ b/docs/understanding-results.md
@@ -22,16 +22,17 @@ For an always up-to-date definition of the LHR, take a look [at our typedefs](ht
 | [timing](#timing) | An object containing information about how long Lighthouse spent auditing. |
 | [categories](#categories) | An object containing the different categories, their scores, and references to the audits that comprise them. |
 | [categoryGroups](#category-groups) | An object containing the display groups of audits for the report. |
+| runtimeError | An object `{code: string, message: string};` providing a top-level error message that, if present, indicates a serious enough problem that this Lighthouse result may need to be discarded. |
+| runWarnings | Array of top-level warnings for this Lighthouse run. |
 
 ### Example
 ```json
 {
-  "lighthouseVersion": "2.4.0",
-  "fetchTime": "2017-10-05T20:50:54.185Z",
-  "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3233.0 Safari/537.36",
+  "lighthouseVersion": "5.1.0",
+  "fetchTime": "2019-05-05T20:50:54.185Z",
+  "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3358.0 Safari/537.36",
   "requestedUrl": "http://example.com",
   "finalUrl": "https://www.example.com/",
-  "score": 50,
   "audits": {...},
   "configSettings": {...},
   "timing": {...},
@@ -56,10 +57,10 @@ An object containing the results of the audits, keyed by their name.
 | warnings | <code>string[]&#124;undefined</code> | Messages identifying potentially invalid cases |
 | errorMessage | <code>string&#124;undefined</code> | A message set |
 | numericValue | <code>number&#124;undefined</code> | The unscored value determined by the audit. Typically this will match the score if there's no additional information to impart. For performance audits, this value is typically a number indicating the metric value. |
-| displayValue | `string` | The string to display in the report alongside audit results. If empty, nothing additional is shown. This is typically used to explain additional information such as the number and nature of failing items. |
-| score | <code>number</code> | The scored value determined by the audit as a number `0-1`, representing displayed scores of 0-100. |
-| scoreDisplayMode | <code>"binary"&#124;"numeric"&#124;"error"&#124;"manual"&#124;"notApplicable"&#124;"informative"</code> | A string identifying how the score should be interpreted for display i.e. is the audit pass/fail (score of 1 or 0), did it fail, should it be ignored, or are there shades of gray (scores between 0-1 inclusive). |
-| details | `Object` | Extra information found by the audit necessary for display. The structure of this object varies from audit to audit. The structure of this object is somewhat stable between minor version bumps as this object is used to render the HTML report. |
+| displayValue | <code>string&#124;undefined</code> | The string to display in the report alongside audit results. If empty, nothing additional is shown. This is typically used to explain additional information such as the number and nature of failing items. |
+| score | <code>number&#124;null</code> | The scored value determined by the audit provided in the numeric range `0-1`, or null if `scoreDisplayMode` indicates not scored. |
+| scoreDisplayMode | <code>"binary" &#124; "numeric" &#124; "error" &#124; "manual" &#124; "notApplicable" &#124; "informative"</code> | A string identifying how the score should be interpreted for display i.e. is the audit pass/fail (score of 1 or 0), did it fail, should it be ignored, or are there shades of gray (scores between 0-1 inclusive). If set as `informative`, `notApplicable`, `manual`, or `error`, then `score` will be null and should be ignored. |
+| details | `Object` | Extra information found by the audit necessary for display. The structure of this object varies from audit to audit. The [structure of this object](https://github.com/GoogleChrome/lighthouse/blob/master/types/audit-details.d.ts) is somewhat stable between minor version bumps as this object is used to render the HTML report. |
 
 
 ### Example
diff --git a/lighthouse-core/gather/gather-runner.js b/lighthouse-core/gather/gather-runner.js
index deb8d4611..36216a074 100644
--- a/lighthouse-core/gather/gather-runner.js
+++ b/lighthouse-core/gather/gather-runner.js
@@ -622,6 +622,18 @@ class GatherRunner {
     return !settings.disableStorageReset && passConfig.recordTrace && passConfig.useThrottling;
   }
 
+  /**
+   * Save the devtoolsLog and trace (if applicable) to baseArtifacts.
+   * @param {LH.Gatherer.PassContext} passContext
+   * @param {LH.Gatherer.LoadData} loadData
+   * @param {string} passName
+   */
+  static _addLoadDataToBaseArtifacts(passContext, loadData, passName) {
+    const baseArtifacts = passContext.baseArtifacts;
+    baseArtifacts.devtoolsLogs[passName] = loadData.devtoolsLog;
+    if (loadData.trace) baseArtifacts.traces[passName] = loadData.trace;
+  }
+
   /**
    * Starting from about:blank, load the page and run gatherers for this pass.
    * @param {LH.Gatherer.PassContext} passContext
@@ -648,20 +660,20 @@ class GatherRunner {
     // Disable throttling so the afterPass analysis isn't throttled
     await driver.setThrottling(passContext.settings, {useThrottling: false});
 
-    // Save devtoolsLog and trace.
-    const baseArtifacts = passContext.baseArtifacts;
-    baseArtifacts.devtoolsLogs[passConfig.passName] = loadData.devtoolsLog;
-    if (loadData.trace) baseArtifacts.traces[passConfig.passName] = loadData.trace;
-
     // If there were any load errors, treat all gatherers as if they errored.
     const pageLoadError = GatherRunner.getPageLoadError(passContext, loadData, possibleNavError);
     if (pageLoadError) {
       log.error('GatherRunner', pageLoadError.friendlyMessage, passContext.url);
       passContext.LighthouseRunWarnings.push(pageLoadError.friendlyMessage);
+      GatherRunner._addLoadDataToBaseArtifacts(passContext, loadData,
+          `pageLoadError-${passConfig.passName}`);
       return GatherRunner.generatePageLoadErrorArtifacts(passContext, pageLoadError);
     }
 
-    // If no error, run `afterPass()` on gatherers and return collected artifacts.
+    // If no error, save devtoolsLog and trace.
+    GatherRunner._addLoadDataToBaseArtifacts(passContext, loadData, passConfig.passName);
+
+    // Run `afterPass()` on gatherers and return collected artifacts.
     await GatherRunner.afterPass(passContext, loadData, gathererResults);
     return GatherRunner.collectArtifacts(gathererResults);
   }
diff --git a/lighthouse-core/report/html/report-styles.css b/lighthouse-core/report/html/report-styles.css
index d1752a9dc..8f0f3208d 100644
--- a/lighthouse-core/report/html/report-styles.css
+++ b/lighthouse-core/report/html/report-styles.css
@@ -15,116 +15,133 @@
  * limitations under the License.
  */
 
-.lh-vars {
-  --text-font-family: Roboto, Helvetica, Arial, sans-serif;
-  --monospace-font-family: 'Roboto Mono', 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;
-  --body-background-color: #fff;
-  --body-text-color: var(--color-black-900);
-  --body-font-size: 16px;
-  --body-line-height: 24px;
-  --subheader-color: hsl(206, 6%, 25%);
-  --header-font-size: 20px;
-  --header-line-height: 24px;
-  --caption-line-height: 16px;
-  --default-padding: 12px;
-  --section-padding: 16px;
-  --section-indent: 16px;
-  --audit-item-gap: 5px;
-  --text-indent: 8px;
-  --secondary-text-color: var(--color-black-800);
-  --informative-color: var(--color-blue-900);
-  --medium-75-gray: #757575;
-  --medium-50-gray: hsl(210, 17%, 98%);
-  --report-secondary-border-color: #ebebeb;
-  --display-value-gray: hsl(216, 5%, 39%);
-  --report-width: calc(60 * var(--body-font-size));
-  --report-min-width: 400px;
-  --lh-score-icon-background-size: 24px;
-  --lh-tools-icon-size: var(--lh-score-icon-background-size);
-  --lh-tools-icon-color: var(--medium-75-gray);
-  --lh-table-higlight-bg: hsla(0, 0%, 75%, 0.1);
-  --lh-sparkline-height: 5px;
-  --lh-audit-vpadding: 8px;
-  --lh-audit-group-vpadding: 8px;
-  --lh-section-vpadding: 12px;
-  --chevron-size: 12px;
-  --inner-audit-left-padding: calc(var(--score-shape-size) + var(--score-shape-margin-left) + var(--score-shape-margin-right));
+/*
+  Naming convention:
+
+  If a variable is used for a specific component: --{component}-{property name}-{modifier}
+
+  Both {component} and {property name} should be kebab-case. If the target is the entire page,
+  use 'report' for the component. The property name should not be abbreviated. Use the
+  property name the variable is intended for - if it's used for multiple, a common descriptor
+  is fine (ex: 'size' for a variable applied to 'width' and 'height'). If a variable is shared
+  across multiple components, either create more variables or just drop the "{component}-"
+  part of the name. Append any modifiers at the end (ex: 'big', 'dark').
 
+  For colors: --color-{hue}-{intensity}
+
+  {intensity} is the Material Design tag - 700, A700, etc. Omit "-{intensity}" if there is only one
+  color of that hue.
+*/
+.lh-vars {
   /* Palette using Material Design Colors
    * https://www.materialui.co/colors */
-  --color-black-100: #F5F5F5;
-  --color-black-200: #E0E0E0;
-  --color-black-400: #BDBDBD;
-  --color-black-500: #9E9E9E;
-  --color-black-600: #757575;
-  --color-black-800: #424242;
-  --color-black-900: #212121;
-  --color-black: #000000;
-  --color-blue: #2962FF;
+  --color-blue-200: #90CAF9;
+  --color-blue-900: #0D47A1;
+  --color-blue-A700: #2962FF;
+  --color-cyan-500: #00BCD4;
+  --color-gray-100: #F5F5F5;
+  --color-gray-200: #E0E0E0;
+  --color-gray-400: #BDBDBD;
+  --color-gray-50: #FAFAFA;
+  --color-gray-500: #9E9E9E;
+  --color-gray-600: #757575;
+  --color-gray-800: #424242;
+  --color-gray-900: #212121;
+  --color-gray: #000000;
   --color-green-700: #018642;
   --color-green: #0CCE6B;
   --color-orange-700: #D04900;
   --color-orange: #FFA400;
   --color-red-700: #EB0F00;
   --color-red: #FF4E42;
-  --color-white: #FFFFFF;
-  --color-blue-200: #90CAF9;
-  --color-blue-900: #0D47A1;
-  --color-cyan-500: #00BCD4;
   --color-teal-600: #00897B;
+  --color-white: #FFFFFF;
 
-
-  /* TODO(cjamcl) clean up unused variables. */
-  --audits-margin-bottom: 40px;
-  --env-item-bg: var(--color-black-100);
+  /* Context-specific colors */
+  --color-average-secondary: var(--color-orange-700);
+  --color-average: var(--color-orange);
+  --color-fail-secondary: var(--color-red-700);
+  --color-fail: var(--color-red);
+  --color-informative: var(--color-blue-900);
+  --color-pass-secondary: var(--color-green-700);
+  --color-pass: var(--color-green);
+  --color-hover: var(--color-gray-50);
+
+  /* Component variables */
+  --audit-description-padding-left: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right));
+  --audit-explanation-line-height: 16px;
+  --audit-group-margin-bottom: 40px;
+  --audit-group-padding-vertical: 8px;
+  --audit-margin-horizontal: 5px;
+  --audit-padding-vertical: 8px;
+  --category-header-font-size: 20px;
+  --category-padding: 40px;
+  --chevron-line-stroke: var(--color-gray-600);
+  --chevron-size: 12px;
+  --default-padding: 12px;
+  --env-item-background-color: var(--color-gray-100);
+  --env-item-font-size: 28px;
+  --env-item-line-height: 36px;
+  --env-item-padding: 10px 0px;
   --env-name-min-width: 220px;
-  --env-tem-padding: 10px 0px;
-  --expandable-padding: 0 0 2px calc(var(--score-shape-margin-left) + var(--score-shape-size) + var(--score-shape-margin-right));
+  --footer-padding-vertical: 16px;
   --gauge-circle-size-big: 112px;
   --gauge-circle-size: 80px;
-  --header-padding: 20px 0 20px 0;
-  --icon-square-size: calc(var(--score-shape-size) * 0.88);
-  --plugin-badge-bg: var(--color-white);
+  --gauge-label-font-size-big: 28px;
+  --gauge-label-font-size: 20px;
+  --gauge-label-line-height-big: 36px;
+  --gauge-label-line-height: 26px;
+  --gauge-percentage-font-size-big: 38px;
+  --gauge-percentage-font-size: 28px;
+  --gauge-wrapper-width: 148px;
+  --header-line-height: 24px;
+  --highlighter-background-color: var(--report-text-color);
+  --icon-square-size: calc(var(--score-icon-size) * 0.88);
+  --metric-description-padding: 0 0 2px calc(var(--score-icon-margin-left) + var(--score-icon-size) + var(--score-icon-margin-right));
+  --metric-toggle-lines-fill: #7F7F7F;
+  --metrics-toggle-background-color: var(--color-gray-200);
+  --plugin-badge-background-color: var(--color-white);
   --plugin-badge-size-big: calc(var(--gauge-circle-size-big) / 2.7);
   --plugin-badge-size: calc(var(--gauge-circle-size) / 2.7);
   --plugin-icon-size: 65%;
   --pwa-icon-margin: 0 6px 0 -2px;
-  --pwa-icon-size: var(--topbar-icon-size);
+  --pwa-icon-size: var(--topbar-logo-size);
+  --report-background-color: #fff;
+  --report-border-color-secondary: #ebebeb;
+  --report-font-family-monospace: 'Roboto Mono', 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;
+  --report-font-family: Roboto, Helvetica, Arial, sans-serif;
+  --report-font-size: 16px;
+  --report-line-height: 24px;
+  --report-min-width: 400px;
+  --report-text-color-secondary: var(--color-gray-800);
+  --report-text-color: var(--color-gray-900);
+  --report-width: calc(60 * var(--report-font-size));
   --score-container-padding: 8px;
-  --score-container-width: 148px;
-  --score-number-font-size-big: 38px;
-  --score-number-font-size: 28px;
-  --score-shape-margin-left: 4px;
-  --score-shape-margin-right: 12px;
-  --score-shape-margin: 0 var(--score-shape-margin-right) 0 var(--score-shape-margin-left);
-  --score-shape-size: 12px;
-  --score-title-font-size-big: 28px;
-  --score-title-font-size: 20px;
-  --score-title-line-height-big: 36px;
-  --score-title-line-height: 26px;
+  --score-icon-background-size: 24px;
+  --score-icon-margin-left: 4px;
+  --score-icon-margin-right: 12px;
+  --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);
+  --score-icon-size: 12px;
+  --scores-container-padding: 20px 0 20px 0;
   --scorescale-height: 6px;
   --scorescale-width: 18px;
-  --section-padding: 40px;
-  --topbar-bg: var(--color-black-100);
+  --section-padding-vertical: 12px;
+  --snippet-background-color: var(--color-gray-50);
+  --snippet-color: var(--color-gray-800);
+  --sparkline-height: 5px;
+  --stackpack-padding-horizontal: 10px;
+  --sticky-header-background-color: var(--report-background-color);
+  --table-higlight-background-color: hsla(0, 0%, 75%, 0.1);
+  --tools-icon-color: var(--color-gray-600);
+  --tools-icon-size: var(--score-icon-background-size);
+  --topbar-background-color: var(--color-gray-100);
   --topbar-height: 32px;
-  --topbar-icon-size: 24px;
+  --topbar-logo-size: 24px;
   --topbar-padding: 0 8px;
-  --metrics-toggle-color: var(--color-black-200);
 
-  --color-average-secondary: var(--color-orange-700);
-  --color-average: var(--color-orange);
-  --color-fail-secondary: var(--color-red-700);
-  --color-fail: var(--color-red);
-  --color-pass-secondary: var(--color-green-700);
-  --color-pass: var(--color-green);
-  --color-sticky-header-bg: var(--body-background-color);
-  --color-highlighter-bg: var(--body-text-color);
-
-  --color-hover: #FAFAFA;
-  --color-metric-toggle-lines: #7F7F7F;
-
-  --plugin-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="%23757575"><path d="M0 0h24v24H0z" fill="none"/><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/></svg>');
+  /* SVGs */
   --plugin-icon-url-dark: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="%23FFFFFF"><path d="M0 0h24v24H0z" fill="none"/><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/></svg>');
+  --plugin-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="%23757575"><path d="M0 0h24v24H0z" fill="none"/><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"/></svg>');
 
   --pass-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>check</title><path fill="%23178239" d="M24 4C12.95 4 4 12.95 4 24c0 11.04 8.95 20 20 20 11.04 0 20-8.96 20-20 0-11.05-8.96-20-20-20zm-4 30L10 24l2.83-2.83L20 28.34l15.17-15.17L38 16 20 34z"/></svg>');
   --average-icon-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><title>info</title><path fill="%23E67700" d="M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm2 30h-4V22h4v12zm0-16h-4v-4h4v4z"/></svg>');
@@ -145,33 +162,31 @@
 
 @media not print {
   .lh-vars.dark {
-    --color-red-700: var(--color-red);
+    /* Pallete */
+    --color-gray-200: var(--color-gray-800);
+    --color-gray-400: var(--color-gray-600);
+    --color-gray-50: #757575;
+    --color-gray-600: var(--color-gray-500);
     --color-green-700: var(--color-green);
-    --color-teal-600: var(--color-cyan-500);
     --color-orange-700: var(--color-orange);
-  
-    --color-black-200: var(--color-black-800);
-    --color-black-400: var(--color-black-600);
-    --color-black-600: var(--color-black-500);
-  
-    --topbar-bg: var(--color-black);
-    --plugin-badge-bg: var(--color-black-800);
-    --env-item-bg: var(--color-black);
-    --report-secondary-border-color: var(--color-black-200);
-  
-    --body-background-color: var(--color-black-900);
-    --body-text-color: var(--color-black-100);
-    --secondary-text-color: var(--color-black-400);
-  
-    --plugin-icon-url: var(--plugin-icon-url-dark);
-  
-    --informative-color: var(--color-blue-200);
-  
-    --medium-50-gray: #757575;
-    --medium-75-gray: var(--color-white);
-  
+    --color-red-700: var(--color-red);
+    --color-teal-600: var(--color-cyan-500);
+
+    /* Context-specific colors */
     --color-hover: rgba(0, 0, 0, 0.2);
-  
+    --color-informative: var(--color-blue-200);
+
+    /* Component variables */
+    --env-item-background-color: var(--color-gray);
+    --plugin-badge-background-color: var(--color-gray-800);
+    --report-background-color: var(--color-gray-900);
+    --report-border-color-secondary: var(--color-gray-200);
+    --report-text-color-secondary: var(--color-gray-400);
+    --report-text-color: var(--color-gray-100);
+    --topbar-background-color: var(--color-gray);
+
+    /* SVGs */
+    --plugin-icon-url: var(--plugin-icon-url-dark);
     --pwa-fast-reliable-gray-url: var(--pwa-fast-reliable-gray-url-dark);
     --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark);
     --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark);
@@ -180,27 +195,27 @@
 
 @media only screen and (max-width: 480px) {
   .lh-vars {
-    --audits-margin-bottom: 20px;
-    --body-font-size: 14px;
-    --body-line-height: 20px;
+    --audit-group-margin-bottom: 20px;
+    --category-padding: 24px;
     --env-name-min-width: 120px;
     --gauge-circle-size-big: 96px;
     --gauge-circle-size: 72px;
+    --gauge-label-font-size-big: 22px;
+    --gauge-label-font-size: 14px;
+    --gauge-label-line-height-big: 26px;
+    --gauge-label-line-height: 20px;
+    --gauge-percentage-font-size-big: 34px;
+    --gauge-percentage-font-size: 26px;
+    --gauge-wrapper-width: 112px;
     --header-padding: 16px 0 16px 0;
     --plugin-icon-size: 75%;
     --pwa-icon-margin: 0 7px 0 -3px;
-    --score-container-width: 112px;
-    --score-number-font-size-big: 34px;
-    --score-number-font-size: 26px;
-    --score-shape-margin-left: 2px;
-    --score-shape-size: 10px;
-    --score-title-font-size-big: 22px;
-    --score-title-font-size: 14px;
-    --score-title-line-height-big: 26px;
-    --score-title-line-height: 20px;
-    --section-padding: 24px;
+    --report-font-size: 14px;
+    --report-line-height: 20px;
+    --score-icon-margin-left: 2px;
+    --score-icon-size: 10px;
     --topbar-height: 28px;
-    --topbar-icon-size: 20px;
+    --topbar-logo-size: 20px;
   }
 
   /* Not enough space to adequately show the relative savings bars. */
@@ -210,38 +225,35 @@
 }
 
 .lh-vars.lh-devtools {
-  --text-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;
-  --monospace-font-family: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;
-  --body-font-size: 12px;
-  --body-line-height: 20px;
-  --header-font-size: 16px;
-  --header-line-height: 20px;
-  --caption-line-height: 14px;
+  --audit-explanation-line-height: 14px;
+  --audit-group-margin-bottom: 20px;
+  --audit-group-padding-vertical: 12px;
+  --audit-padding-vertical: 4px;
+  --category-header-font-size: 16px;
+  --category-padding: 12px;
   --default-padding: 12px;
-  --section-padding: 12px;
-  --section-indent: 8px;
-
+  --env-name-min-width: 120px;
+  --footer-padding-vertical: 8px;
   --gauge-circle-size-big: 72px;
   --gauge-circle-size: 64px;
-
-  --audits-margin-bottom: 20px;
-  --env-name-min-width: 120px;
+  --gauge-label-font-size-big: 22px;
+  --gauge-label-font-size: 14px;
+  --gauge-label-line-height-big: 26px;
+  --gauge-label-line-height: 20px;
+  --gauge-percentage-font-size-big: 34px;
+  --gauge-percentage-font-size: 26px;
+  --gauge-wrapper-width: 97px;
+  --header-line-height: 20px;
   --header-padding: 16px 0 16px 0;
   --plugin-icon-size: 75%;
   --pwa-icon-margin: 0 7px 0 -3px;
-  --score-container-width: 97px;
-  --score-number-font-size-big: 34px;
-  --score-number-font-size: 26px;
-  --score-shape-margin-left: 2px;
-  --score-shape-size: 10px;
-  --score-title-font-size-big: 22px;
-  --score-title-font-size: 14px;
-  --score-title-line-height-big: 26px;
-  --score-title-line-height: 20px;
-
-  --lh-audit-vpadding: 4px;
-  --lh-audit-group-vpadding: 12px;
-  --lh-section-vpadding: 8px;
+  --report-font-family-monospace: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;
+  --report-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;
+  --report-font-size: 12px;
+  --report-line-height: 20px;
+  --score-icon-margin-left: 2px;
+  --score-icon-size: 10px;
+  --section-padding-vertical: 8px;
 }
 
 .lh-devtools.lh-root {
@@ -267,13 +279,13 @@
 }
 
 .lh-root {
-  font-family: var(--text-font-family);
-  font-size: var(--body-font-size);
+  font-family: var(--report-font-family);
+  font-size: var(--report-font-size);
   margin: 0;
-  line-height: var(--body-line-height);
-  background: var(--body-background-color);
+  line-height: var(--report-line-height);
+  background: var(--report-background-color);
   scroll-behavior: smooth;
-  color: var(--body-text-color);
+  color: var(--report-text-color);
 }
 
 .lh-root :focus {
@@ -317,22 +329,22 @@
 .lh-category-header__description a,
 .lh-audit__description a,
 .lh-footer a {
-  color: var(--informative-color);
+  color: var(--color-informative);
 }
 
 .lh-audit__description, .lh-audit__stackpack {
-  --inner-audit-right-padding: calc(var(--text-indent) + 2px);
-  padding-left: var(--inner-audit-left-padding);
-  padding-right: var(--inner-audit-right-padding);
+  --inner-audit-padding-right: var(--stackpack-padding-horizontal);
+  padding-left: var(--audit-description-padding-left);
+  padding-right: var(--inner-audit-padding-right);
   padding-top: 8px;
   padding-bottom: 8px;
 }
 
 .lh-details {
-  font-size: var(--body-font-size);
+  font-size: var(--report-font-size);
   margin-top: var(--default-padding);
   margin-bottom: var(--default-padding);
-  margin-left: var(--inner-audit-left-padding);
+  margin-left: var(--audit-description-padding-left);
   /* whatever the .lh-details side margins are */
   width: 100%;
 }
@@ -382,7 +394,7 @@
 
 /* Node */
 .lh-node__snippet {
-  font-family: var(--monospace-font-family);
+  font-family: var(--report-font-family-monospace);
   color: var(--color-teal-600);
   font-size: 12px;
   line-height: 1.5em;
@@ -391,9 +403,9 @@
 /* Score */
 
 .lh-audit__score-icon {
-  width: var(--score-shape-size);
-  height: var(--score-shape-size);
-  margin: var(--score-shape-margin);
+  width: var(--score-icon-size);
+  height: var(--score-icon-size);
+  margin: var(--score-icon-margin);
 }
 
 .lh-audit--pass .lh-audit__display-text {
@@ -417,19 +429,19 @@
   color: var(--color-fail-secondary);
 }
 .lh-audit--fail .lh-audit__score-icon {
-  border-left: calc(var(--score-shape-size) / 2) solid transparent;
-  border-right: calc(var(--score-shape-size) / 2) solid transparent;
-  border-bottom: var(--score-shape-size) solid var(--color-fail);
+  border-left: calc(var(--score-icon-size) / 2) solid transparent;
+  border-right: calc(var(--score-icon-size) / 2) solid transparent;
+  border-bottom: var(--score-icon-size) solid var(--color-fail);
 }
 
 .lh-audit--manual .lh-audit__display-text,
 .lh-audit--notapplicable .lh-audit__display-text {
-  color: var(--color-black-600);
+  color: var(--color-gray-600);
 }
 .lh-audit--manual .lh-audit__score-icon,
 .lh-audit--notapplicable .lh-audit__score-icon {
   border-radius: 100%;
-  background: var(--color-black-400);
+  background: var(--color-gray-400);
 }
 
 .lh-audit--error .lh-audit__score-icon {
@@ -437,21 +449,21 @@
 }
 
 .lh-audit--informative .lh-audit__display-text {
-  color: var(--color-black-600);
+  color: var(--color-gray-600);
 }
 
 .lh-audit--informative .lh-audit__score-icon {
   border: none;
   border-radius: 100%;
-  background: var(--color-black-400);
+  background: var(--color-gray-400);
 }
 
 .lh-audit__description,
 .lh-audit__stackpack {
-  color: var(--secondary-text-color);
+  color: var(--report-text-color-secondary);
 }
 .lh-category-header__description  {
-  font-size: var(--body-font-size);
+  font-size: var(--report-font-size);
   text-align: center;
   margin: 0px auto;
   max-width: 400px;
@@ -461,7 +473,7 @@
 .lh-audit__display-text,
 .lh-load-opportunity__sparkline,
 .lh-chevron-container {
-  margin: 0 var(--audit-item-gap);
+  margin: 0 var(--audit-margin-horizontal);
 }
 .lh-chevron-container {
   margin-right: 0;
@@ -474,7 +486,7 @@
 /* Prepend display text with em dash separator. But not in Opportunities. */
 .lh-audit__display-text:not(:empty):before {
   content: '—';
-  margin-right: var(--audit-item-gap);
+  margin-right: var(--audit-margin-horizontal);
 }
 .lh-audit-group.lh-audit-group--load-opportunities .lh-audit__display-text:not(:empty):before {
   display: none;
@@ -485,7 +497,7 @@
   display: flex;
   align-items: center;
   font-weight: 500;
-  padding: var(--lh-audit-vpadding) 0;
+  padding: var(--audit-padding-vertical) 0;
 }
 
 .lh-audit--load-opportunity .lh-audit__header {
@@ -551,10 +563,10 @@
 
 
 .lh-metric {
-  border-bottom: 1px solid var(--report-secondary-border-color);
+  border-bottom: 1px solid var(--report-border-color-secondary);
 }
 .lh-metric:first-of-type {
-  border-top: 1px solid var(--report-secondary-border-color);
+  border-top: 1px solid var(--report-border-color-secondary);
 }
 
 .lh-metric__innerwrap {
@@ -575,14 +587,14 @@
 }
 
 .lh-metrics__disclaimer {
-  color: var(--medium-75-gray);
-  margin: var(--lh-section-vpadding) 0;
+  color: var(--color-gray-600);
+  margin: var(--section-padding-vertical) 0;
 }
 
 .lh-metric__description {
   display: none;
-  color: var(--secondary-text-color);
-  padding: var(--expandable-padding);
+  color: var(--report-text-color-secondary);
+  padding: var(--metric-description-padding);
 }
 
 .lh-metric__value {
@@ -628,15 +640,15 @@
 }
 .lh-metrics-toggle__input:not(:checked) + label .lh-metrics-toggle__icon--less,
 .lh-metrics-toggle__input:checked + label .lh-metrics-toggle__icon--more {
-  background-color: var(--color-blue);
-  --color-metric-toggle-lines: var(--color-white);
+  background-color: var(--color-blue-A700);
+  --metric-toggle-lines-fill: var(--color-white);
 }
 .lh-metrics-toggle__lines {
-  fill: var(--color-metric-toggle-lines);
+  fill: var(--metric-toggle-lines-fill);
 }
 
 .lh-metrics-toggle__label  {
-  background-color: var(--metrics-toggle-color);
+  background-color: var(--metrics-toggle-background-color);
 }
 
 .lh-metrics-toggle__label .lh-metrics-toggle__icon--less {
@@ -656,10 +668,10 @@
 
 .lh-metric .lh-metric__innerwrap::before {
   content: '';
-  width: var(--score-shape-size);
-  height: var(--score-shape-size);
+  width: var(--score-icon-size);
+  height: var(--score-icon-size);
   display: inline-block;
-  margin: var(--score-shape-margin);
+  margin: var(--score-icon-margin);
 }
 
 .lh-metric--pass .lh-metric__value {
@@ -683,9 +695,9 @@
   color: var(--color-fail-secondary);
 }
 .lh-metric--fail .lh-metric__innerwrap::before {
-  border-left: calc(var(--score-shape-size) / 2) solid transparent;
-  border-right: calc(var(--score-shape-size) / 2) solid transparent;
-  border-bottom: var(--score-shape-size) solid var(--color-fail);
+  border-left: calc(var(--score-icon-size) / 2) solid transparent;
+  border-right: calc(var(--score-icon-size) / 2) solid transparent;
+  border-bottom: var(--score-icon-size) solid var(--color-fail);
 }
 
 .lh-metric--error .lh-metric__value,
@@ -706,9 +718,9 @@
 }
 
 .lh-load-opportunity__header .lh-load-opportunity__col {
-  color: var(--medium-75-gray);
+  color: var(--color-gray-600);
   display: unset;
-  line-height: calc(2.3 * var(--body-font-size));
+  line-height: calc(2.3 * var(--report-font-size));
 }
 
 .lh-load-opportunity__col {
@@ -727,7 +739,7 @@
 
 .lh-audit--load-opportunity .lh-audit__display-text {
   text-align: right;
-  flex: 0 0 calc(3 * var(--body-font-size));
+  flex: 0 0 calc(3 * var(--report-font-size));
 }
 
 
@@ -735,11 +747,11 @@
 
 .lh-load-opportunity__sparkline {
   flex: 1;
-  margin-top: calc((var(--body-line-height) - var(--lh-sparkline-height)) / 2);
+  margin-top: calc((var(--report-line-height) - var(--sparkline-height)) / 2);
 }
 
 .lh-sparkline {
-  height: var(--lh-sparkline-height);
+  height: var(--sparkline-height);
   width: 100%;
 }
 
@@ -782,7 +794,7 @@
 }
 
 .lh-filmstrip__thumbnail {
-  border: 1px solid var(--report-secondary-border-color);
+  border: 1px solid var(--report-border-color-secondary);
   max-height: 100px;
   max-width: 60px;
 }
@@ -804,12 +816,12 @@
 /* Audit */
 
 .lh-audit {
-  border-bottom: 1px solid var(--report-secondary-border-color);
+  border-bottom: 1px solid var(--report-border-color-secondary);
 }
 
 /* Apply border-top to just the first audit. */
 .lh-audit {
-  border-top: 1px solid var(--report-secondary-border-color);
+  border-top: 1px solid var(--report-border-color-secondary);
 }
 .lh-audit ~ .lh-audit {
   border-top: none;
@@ -823,7 +835,7 @@
 /* Audit Group */
 
 .lh-audit-group {
-  margin-bottom: var(--audits-margin-bottom);
+  margin-bottom: var(--audit-group-margin-bottom);
   position: relative;
 }
 
@@ -882,22 +894,21 @@
 .lh-audit-group__summary {
   display: flex;
   justify-content: space-between;
-  padding-right: var(--text-indent);
-  margin-top: calc(var(--section-padding) * 1.5);
-  margin-bottom: var(--section-padding);
+  margin-top: calc(var(--category-padding) * 1.5);
+  margin-bottom: var(--category-padding);
 }
 
 .lh-audit-group__itemcount {
-  color: var(--color-black-600);
+  color: var(--color-gray-600);
   font-weight: bold;
 }
 .lh-audit-group__header .lh-chevron {
-  margin-top: calc((var(--body-line-height) - 5px) / 2);
+  margin-top: calc((var(--report-line-height) - 5px) / 2);
 }
 
 .lh-audit-group__header {
-  font-size: var(--body-font-size);
-  margin: 0 0 var(--lh-audit-group-vpadding);
+  font-size: var(--report-font-size);
+  margin: 0 0 var(--audit-group-padding-vertical);
   /* When the header takes 100% width, the chevron becomes small. */
   max-width: calc(100% - var(--chevron-size));
 }
@@ -912,16 +923,16 @@
 
 .lh-audit-group__header span.lh-audit-group__itemcount {
   font-weight: bold;
-  color: var(--color-black-600);
+  color: var(--color-gray-600);
 }
 
 .lh-audit-group__header span.lh-audit-group__description {
   font-weight: 500;
-  color: var(--color-black-600);
+  color: var(--color-gray-600);
 }
 .lh-audit-group__header span.lh-audit-group__description::before {
   content: '—';
-  margin: 0px var(--audit-item-gap);
+  margin: 0px var(--audit-margin-horizontal);
 }
 
 .lh-clump > .lh-audit-group__header,
@@ -931,12 +942,12 @@
 .lh-audit-group--pwa-fast-reliable .lh-audit-group__header,
 .lh-audit-group--pwa-installable .lh-audit-group__header,
 .lh-audit-group--pwa-optimized .lh-audit-group__header {
-  margin-top: var(--lh-audit-group-vpadding);
+  margin-top: var(--audit-group-padding-vertical);
 }
 
 .lh-audit-explanation {
-  margin: var(--lh-audit-vpadding) 0 calc(var(--lh-audit-vpadding) / 2);
-  line-height: var(--caption-line-height);
+  margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2);
+  line-height: var(--audit-explanation-line-height);
 }
 
 .lh-audit--fail .lh-audit-explanation {
@@ -970,10 +981,10 @@
 }
 
 .lh-warnings {
-  --item-margin: calc(var(--body-line-height) / 6);
+  --item-margin: calc(var(--report-line-height) / 6);
   color: var(--color-average);
-  margin: var(--lh-audit-vpadding) 0;
-  padding: calc(var(--lh-audit-vpadding) / 2) var(--lh-audit-vpadding);
+  margin: var(--audit-padding-vertical) 0;
+  padding: calc(var(--audit-padding-vertical) / 2) var(--audit-padding-vertical);
 }
 .lh-warnings span {
   font-weight: bold;
@@ -981,12 +992,12 @@
 
 .lh-warnings--toplevel {
   --item-margin: calc(var(--header-line-height) / 4);
-  color: var(--secondary-text-color);
-  margin: var(--section-padding);
-  padding: var(--section-padding);
+  color: var(--report-text-color-secondary);
+  margin: var(--category-padding);
+  padding: var(--category-padding);
 }
 .lh-warnings ul {
-  padding-left: calc(var(--section-padding) * 2);
+  padding-left: calc(var(--category-padding) * 2);
   margin: 0;
 }
 .lh-warnings li {
@@ -1062,7 +1073,7 @@
 .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-color: var(--plugin-badge-background-color);
   background-image: var(--plugin-icon-url);
   background-repeat: no-repeat;
   background-size: var(--plugin-icon-size);
@@ -1089,7 +1100,7 @@
   width: 100%;
   height: var(--gauge-circle-size);
   position: absolute;
-  font-family: var(--monospace-font-family);
+  font-family: var(--report-font-family-monospace);
   font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);
   line-height: 0;
   text-align: center;
@@ -1098,7 +1109,7 @@
 
 .lh-category .lh-gauge__percentage {
   --gauge-circle-size: var(--gauge-circle-size-big);
-  --score-number-font-size: var(--score-number-font-size-big);
+  --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);
 }
 
 .lh-gauge__wrapper {
@@ -1118,17 +1129,17 @@
 }
 
 .lh-gauge__label {
-  font-size: var(--score-title-font-size);
-  line-height: var(--score-title-line-height);
+  font-size: var(--gauge-label-font-size);
+  line-height: var(--gauge-label-line-height);
   margin-top: 10px;
   text-align: center;
-  color: var(--body-text-color);
+  color: var(--report-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);
+  --gauge-label-font-size: var(--gauge-label-font-size-big);
+  --gauge-label-line-height: var(--gauge-label-line-height-big);
   margin-top: 14px;
 }
 
@@ -1137,7 +1148,7 @@
 .lh-scores-header .lh-gauge--pwa__wrapper,
 .lh-sticky-header .lh-gauge__wrapper,
 .lh-sticky-header .lh-gauge--pwa__wrapper {
-  width: var(--score-container-width);
+  width: var(--gauge-wrapper-width);
 }
 
 .lh-scores-header .lh-gauge--pwa__wrapper {
@@ -1148,7 +1159,7 @@
 .lh-scorescale {
   display: inline-flex;
   margin: 12px auto 0 auto;
-  border: 1px solid var(--color-black-200);
+  border: 1px solid var(--color-gray-200);
   border-radius: 20px;
   padding: 8px 8px;
 }
@@ -1157,7 +1168,7 @@
   display: flex;
   align-items: center;
   margin: 0 12px;
-  font-family: var(--monospace-font-family);
+  font-family: var(--report-font-family-monospace);
   white-space: nowrap;
 }
 
@@ -1194,17 +1205,17 @@
 }
 
 .lh-category {
-  padding: var(--section-padding);
+  padding: var(--category-padding);
   max-width: var(--report-width);
   margin: 0 auto;
 }
 
 .lh-category-wrapper {
-  border-bottom: 1px solid var(--color-black-200);
+  border-bottom: 1px solid var(--color-gray-200);
 }
 
 .lh-category-wrapper:first-of-type {
-  border-top: 1px solid var(--color-black-200);
+  border-top: 1px solid var(--color-gray-200);
 }
 
 /* section hash link jump should preserve fixed header
@@ -1220,9 +1231,9 @@
 }
 
 .lh-category-header {
-  font-size: var(--header-font-size);
+  font-size: var(--category-header-font-size);
   min-height: var(--gauge-circle-size);
-  margin-bottom: var(--lh-section-vpadding);
+  margin-bottom: var(--section-padding-vertical);
 }
 
 .lh-category-header .lh-score__gauge {
@@ -1232,7 +1243,7 @@
 }
 
 .lh-category-header .lh-audit__title {
-  font-size: var(--header-font-size);
+  font-size: var(--category-header-font-size);
   line-height: var(--header-line-height);
 }
 
@@ -1289,18 +1300,18 @@
   --image-preview-size: 24px;
   border-collapse: collapse;
   /* Can't assign padding to table, so shorten the width instead. */
-  width: calc(100% - var(--inner-audit-left-padding));
+  width: calc(100% - var(--audit-description-padding-left));
 }
 
 .lh-table thead th {
   font-weight: normal;
-  color: var(--color-black-600);
+  color: var(--color-gray-600);
   /* See text-wrapping comment on .lh-container. */
   word-break: normal;
 }
 
 .lh-table tbody tr:nth-child(odd) {
-  background-color: var(--lh-table-higlight-bg);
+  background-color: var(--table-higlight-background-color);
 }
 
 .lh-table th,
@@ -1361,7 +1372,7 @@
 }
 
 .lh-text__url-host {
-  margin-left: calc(var(--body-font-size) / 2);
+  margin-left: calc(var(--report-font-size) / 2);
   opacity: 0.6;
   font-size: 90%
 }
@@ -1381,15 +1392,15 @@
   --chevron-angle-right: -42deg;
   width: var(--chevron-size);
   height: var(--chevron-size);
-  margin-top: calc((var(--body-line-height) - 12px) / 2);
+  margin-top: calc((var(--report-line-height) - 12px) / 2);
 }
 
 .lh-chevron__lines {
   transition: transform 0.4s;
-  transform: translateY(var(--body-line-height));
+  transform: translateY(var(--report-line-height));
 }
 .lh-chevron__line {
- stroke: var(--display-value-gray);
+ stroke: var(--chevron-line-stroke);
  stroke-width: var(--chevron-size);
  stroke-linecap: square;
  transform-origin: 50%;
diff --git a/lighthouse-core/report/html/templates.html b/lighthouse-core/report/html/templates.html
index 11d1d78e0..92f633d0a 100644
--- a/lighthouse-core/report/html/templates.html
+++ b/lighthouse-core/report/html/templates.html
@@ -159,7 +159,7 @@ limitations under the License.
     .lh-scores-container {
       display: flex;
       flex-direction: column;
-      padding: var(--header-padding);
+      padding: var(--scores-container-padding);
       position: relative;
       width: 100%;
     }
@@ -168,8 +168,8 @@ limitations under the License.
       --gauge-circle-size: 36px;
       --plugin-badge-size: 18px;
       --plugin-icon-size: 75%;
-      --score-container-width: 60px;
-      --score-number-font-size: 13px;
+      --gauge-wrapper-width: 60px;
+      --gauge-percentage-font-size: 13px;
       position: sticky;
       left: 0;
       right: 0;
@@ -177,8 +177,8 @@ limitations under the License.
       font-weight: 700;
       display: none;
       justify-content: center;
-      background-color: var(--color-sticky-header-bg);
-      border-bottom: 1px solid var(--color-black-200);
+      background-color: var(--sticky-header-background-color);
+      border-bottom: 1px solid var(--color-gray-200);
       padding-top: var(--score-container-padding);
       padding-bottom: 4px;
       z-index: 1;
@@ -202,9 +202,9 @@ limitations under the License.
     }
 
     .lh-highlighter {
-      width: var(--score-container-width);
+      width: var(--gauge-wrapper-width);
       height: 1px;
-      background: var(--color-highlighter-bg);
+      background-color: var(--highlighter-background-color);
       /* Position at bottom of first gauge in sticky header. */
       position: absolute;
       grid-column: 1;
@@ -237,23 +237,23 @@ limitations under the License.
       display: flex;
       align-items: center;
       height: var(--topbar-height);
-      background-color: var(--topbar-bg);
+      background-color: var(--topbar-background-color);
       padding: var(--topbar-padding);
     }
 
     .lh-topbar__logo {
-      width: var(--topbar-icon-size);
-      height: var(--topbar-icon-size);
+      width: var(--topbar-logo-size);
+      height: var(--topbar-logo-size);
       user-select: none;
     }
     .lh-topbar__logo .shape {
-      fill: var(--body-text-color);
+      fill: var(--report-text-color);
     }
 
     .lh-topbar__url {
       margin: var(--topbar-padding);
       text-decoration: none;
-      color: var(--body-text-color);
+      color: var(--report-text-color);
     }
 
     .lh-tools {
@@ -261,8 +261,8 @@ limitations under the License.
       will-change: transform;
     }
     .lh-tools__button {
-      width: var(--lh-tools-icon-size);
-      height: var(--lh-tools-icon-size);
+      width: var(--tools-icon-size);
+      height: var(--tools-icon-size);
       cursor: pointer;
       margin-right: 5px;
       /* This is actually a button element, but we want to style it like a transparent div. */
@@ -275,7 +275,7 @@ limitations under the License.
       outline: inherit;
     }
     .lh-tools__button svg {
-      fill: var(--lh-tools-icon-color);
+      fill: var(--tools-icon-color);
     }
     .dark .lh-tools__button svg {
       filter: invert(1);
@@ -287,7 +287,7 @@ limitations under the License.
     }
     .lh-tools__dropdown {
       position: absolute;
-      background-color: var(--body-background-color);
+      background-color: var(--report-background-color);
       border: 1px solid var(--report-border-color);
       border-radius: 3px;
       padding: calc(var(--default-padding) / 2) 0;
@@ -311,7 +311,7 @@ limitations under the License.
     }
     .lh-tools__dropdown a:hover,
     .lh-tools__dropdown a:focus {
-      background-color: var(--color-black-200);
+      background-color: var(--color-gray-200);
       outline: none;
     }
     .lh-tools__dropdown .report-icon {
@@ -323,7 +323,7 @@ limitations under the License.
       text-indent: 18px;
     }
     .dark .report-icon {
-      color: var(--color-black-900);
+      color: var(--color-gray-900);
       filter: invert(1);
     }
     .dark .lh-tools__dropdown a:hover,
@@ -494,7 +494,7 @@ limitations under the License.
 <template id="tmpl-lh-footer">
   <style>
     .lh-footer {
-      padding: var(--section-indent) calc(var(--default-padding) * 2);
+      padding: var(--footer-padding-vertical) calc(var(--default-padding) * 2);
       max-width: var(--report-width);
       margin: 0 auto;
     }
@@ -502,8 +502,8 @@ limitations under the License.
       text-align: center;
     }
     .lh-env__title {
-      font-size: var(--score-title-font-size-big);
-      line-height: var(--score-title-line-height-big);
+      font-size: var(--env-item-font-size-big);
+      line-height: var(--env-item-line-height-big);
       text-align: center;
       padding: var(--score-container-padding);
     }
@@ -516,11 +516,11 @@ limitations under the License.
       padding: 0;
     }
     .lh-env__items .lh-env__item:nth-child(2n) {
-      background: var(--env-item-bg);
+      background-color: var(--env-item-background-color);
     }
     .lh-env__item {
       display: flex;
-      padding: var(--env-tem-padding);
+      padding: var(--env-item-padding);
       position: relative;
     }
     span.lh-env__name {
@@ -584,7 +584,7 @@ limitations under the License.
     }
 
     .lh-gauge--pwa__disc {
-      fill: var(--color-black-200);
+      fill: var(--color-gray-200);
     }
 
     .lh-gauge--pwa__logo--primary-color {
@@ -782,8 +782,8 @@ limitations under the License.
 <template id="tmpl-lh-3p-filter">
   <style>
     .lh-3p-filter {
-      background: var(--lh-table-higlight-bg);
-      color: var(--medium-75-gray);
+      background-color: var(--table-higlight-background-color);
+      color: var(--color-gray-600);
       float: right;
       padding: 6px;
     }
@@ -815,9 +815,9 @@ limitations under the License.
           overflow: hidden;
           padding: 10px;
           border-bottom: none;
-          color: var(--subheader-color);
-          background: var(--medium-50-gray);
-          border: 1px solid var(--report-secondary-border-color);
+          color: var(--snippet-color);
+          background-color: var(--snippet-background-color);
+          border: 1px solid var(--report-border-color-secondary);
         }
         .lh-snippet__title {
           font-weight: bold;
@@ -841,7 +841,7 @@ limitations under the License.
 
         .lh-snippet__snippet {
           overflow: auto;
-          border: 1px solid var(--report-secondary-border-color);
+          border: 1px solid var(--report-border-color-secondary);
         }
         /* Container needed so that all children grow to the width of the scroll container */
         .lh-snippet__snippet-inner {
@@ -881,7 +881,7 @@ limitations under the License.
           padding: 10px;
           padding-left: 5px;
           color: var(--color-fail);
-          font-family: var(--text-font-family);
+          font-family: var(--report-font-family);
         }
         .lh-snippet__line--message code {
           white-space: normal;
@@ -898,8 +898,8 @@ limitations under the License.
           display: inline-block;
           vertical-align: middle;
           margin-right: 4px;
-          width: var(--score-shape-size);
-          height: var(--score-shape-size);
+          width: var(--score-icon-size);
+          height: var(--score-icon-size);
           background-image: var(--fail-icon-url);
         }
         .lh-snippet__line-number {
@@ -909,7 +909,7 @@ limitations under the License.
           font-family: monospace;
           padding-right: 5px;
           margin-right: 5px;
-          color: var(--medium-75-gray);
+          color: var(--color-gray-600);
           user-select: none;
         }
       </style>


Test patch:
diff --git a/lighthouse-cli/test/smokehouse/seo/expectations.js b/lighthouse-cli/test/smokehouse/seo/expectations.js
index 098d0f035..0d370cd37 100644
--- a/lighthouse-cli/test/smokehouse/seo/expectations.js
+++ b/lighthouse-cli/test/smokehouse/seo/expectations.js
@@ -216,8 +216,7 @@ module.exports = [
       },
       audits: {
         'http-status-code': {
-          score: 0,
-          displayValue: '403',
+          score: null,
         },
         'viewport': {
           score: null,
diff --git a/lighthouse-core/test/gather/gather-runner-test.js b/lighthouse-core/test/gather/gather-runner-test.js
index 234bd7fd7..533e77646 100644
--- a/lighthouse-core/test/gather/gather-runner-test.js
+++ b/lighthouse-core/test/gather/gather-runner-test.js
@@ -135,34 +135,31 @@ describe('GatherRunner', function() {
   });
 
   it('collects benchmark as an artifact', async () => {
-    const url = 'https://example.com';
+    const requestedUrl = 'https://example.com';
     const driver = fakeDriver;
-    const config = new Config({});
-    const settings = {};
-    const options = {url, driver, config, settings};
+    const config = new Config({passes: []});
+    const options = {requestedUrl, driver, settings: config.settings};
 
-    const results = await GatherRunner.run([], options);
+    const results = await GatherRunner.run(config.passes, options);
     expect(Number.isFinite(results.BenchmarkIndex)).toBeTruthy();
   });
 
   it('collects host user agent as an artifact', async () => {
-    const url = 'https://example.com';
+    const requestedUrl = 'https://example.com';
     const driver = fakeDriver;
-    const config = new Config({});
-    const settings = {};
-    const options = {url, driver, config, settings};
+    const config = new Config({passes: []});
+    const options = {requestedUrl, driver, settings: config.settings};
 
-    const results = await GatherRunner.run([], options);
+    const results = await GatherRunner.run(config.passes, options);
     expect(results.HostUserAgent).toEqual(fakeDriver.protocolGetVersionResponse.userAgent);
     expect(results.HostUserAgent).toMatch(/Chrome\/\d+/);
   });
 
   it('collects network user agent as an artifact', async () => {
-    const url = 'https://example.com';
+    const requestedUrl = 'https://example.com';
     const driver = fakeDriver;
     const config = new Config({passes: [{}]});
-    const settings = {};
-    const options = {url, driver, config, settings};
+    const options = {requestedUrl, driver, settings: config.settings};
 
     const results = await GatherRunner.run(config.passes, options);
     expect(results.NetworkUserAgent).toContain('Mozilla');
@@ -177,8 +174,7 @@ describe('GatherRunner', function() {
       },
     });
     const config = new Config({passes: [{}]});
-    const settings = {};
-    const options = {requestedUrl, driver, config, settings};
+    const options = {requestedUrl, driver, settings: config.settings};
 
     return GatherRunner.run(config.passes, options).then(artifacts => {
       assert.deepStrictEqual(artifacts.URL, {requestedUrl, finalUrl},
@@ -187,13 +183,15 @@ describe('GatherRunner', function() {
   });
 
   describe('collects TestedAsMobileDevice as an artifact', () => {
-    const url = 'https://example.com';
+    const requestedUrl = 'https://example.com';
 
     it('works when running on desktop device without emulation', async () => {
       const driver = fakeDriver;
-      const config = new Config({passes: [{}]});
-      const settings = {};
-      const options = {url, driver, config, settings};
+      const config = new Config({
+        passes: [],
+        settings: {emulatedFormFactor: 'none'},
+      });
+      const options = {requestedUrl, driver, settings: config.settings};
 
       const results = await GatherRunner.run(config.passes, options);
       expect(results.TestedAsMobileDevice).toBe(false);
@@ -201,9 +199,11 @@ describe('GatherRunner', function() {
 
     it('works when running on desktop device with mobile emulation', async () => {
       const driver = fakeDriver;
-      const config = new Config({passes: [{}]});
-      const settings = {emulatedFormFactor: 'mobile'};
-      const options = {url, driver, config, settings};
+      const config = new Config({
+        passes: [],
+        settings: {emulatedFormFactor: 'mobile'},
+      });
+      const options = {requestedUrl, driver, settings: config.settings};
 
       const results = await GatherRunner.run(config.passes, options);
       expect(results.TestedAsMobileDevice).toBe(true);
@@ -211,9 +211,11 @@ describe('GatherRunner', function() {
 
     it('works when running on mobile device without emulation', async () => {
       const driver = fakeDriverUsingRealMobileDevice;
-      const config = new Config({passes: [{}]});
-      const settings = {};
-      const options = {url, driver, config, settings};
+      const config = new Config({
+        passes: [],
+        settings: {emulatedFormFactor: 'none'},
+      });
+      const options = {requestedUrl, driver, settings: config.settings};
 
       const results = await GatherRunner.run(config.passes, options);
       expect(results.TestedAsMobileDevice).toBe(true);
@@ -221,9 +223,11 @@ describe('GatherRunner', function() {
 
     it('works when running on mobile device with desktop emulation', async () => {
       const driver = fakeDriverUsingRealMobileDevice;
-      const config = new Config({passes: [{}]});
-      const settings = {emulatedFormFactor: 'desktop'};
-      const options = {url, driver, config, settings};
+      const config = new Config({
+        passes: [],
+        settings: {emulatedFormFactor: 'desktop'},
+      });
+      const options = {requestedUrl, driver, settings: config.settings};
 
       const results = await GatherRunner.run(config.passes, options);
       expect(results.TestedAsMobileDevice).toBe(false);
@@ -416,7 +420,7 @@ describe('GatherRunner', function() {
       baseArtifacts: await GatherRunner.initializeBaseArtifacts({driver, settings, requestedUrl}),
     };
 
-    await GatherRunner.runPass(passContext, {TestGatherer: []});
+    await GatherRunner.runPass(passContext);
     assert.equal(tests.calledCleanBrowserCaches, true);
   });
 
@@ -588,9 +592,6 @@ describe('GatherRunner', function() {
       beginDevtoolsLog() {
         return Promise.resolve();
       },
-      gotoURL() {
-        return Promise.resolve();
-      },
     };
 
     const passConfig = {
@@ -601,7 +602,7 @@ describe('GatherRunner', function() {
     };
     const settings = {};
 
-    await GatherRunner.beginRecording({driver, passConfig, settings}, {TestGatherer: []});
+    await GatherRunner.beginRecording({driver, passConfig, settings});
     assert.equal(calledTrace, true);
   });
 
@@ -649,7 +650,7 @@ describe('GatherRunner', function() {
     };
     const settings = {};
 
-    await GatherRunner.beginRecording({driver, passConfig, settings}, {TestGatherer: []});
+    await GatherRunner.beginRecording({driver, passConfig, settings});
     assert.equal(calledDevtoolsLogCollect, true);
   });
 
@@ -710,27 +711,26 @@ describe('GatherRunner', function() {
   it('does as many passes as are required', () => {
     const t1 = new TestGatherer();
     const t2 = new TestGatherer();
-    const config = new Config({});
-    const settings = {};
 
-    const passes = [{
-      recordTrace: true,
-      passName: 'firstPass',
-      gatherers: [
-        {instance: t1},
-      ],
-    }, {
-      passName: 'secondPass',
-      gatherers: [
-        {instance: t2},
-      ],
-    }];
+    const config = new Config({
+      passes: [{
+        recordTrace: true,
+        passName: 'firstPass',
+        gatherers: [
+          {instance: t1},
+        ],
+      }, {
+        passName: 'secondPass',
+        gatherers: [
+          {instance: t2},
+        ],
+      }],
+    });
 
-    return GatherRunner.run(passes, {
+    return GatherRunner.run(config.passes, {
       driver: fakeDriver,
       requestedUrl: 'https://example.com',
-      settings,
-      config,
+      settings: config.settings,
     }).then(_ => {
       assert.ok(t1.called);
       assert.ok(t2.called);
@@ -738,18 +738,24 @@ describe('GatherRunner', function() {
   });
 
   it('respects trace names', () => {
-    const passes = [{
-      recordTrace: true,
-      passName: 'firstPass',
-      gatherers: [{instance: new TestGatherer()}],
-    }, {
-      recordTrace: true,
-      passName: 'secondPass',
-      gatherers: [{instance: new TestGatherer()}],
-    }];
-    const options = {driver: fakeDriver, requestedUrl: 'https://example.com', settings: {}, config: {}};
+    const config = new Config({
+      passes: [{
+        recordTrace: true,
+        passName: 'firstPass',
+        gatherers: [{instance: new TestGatherer()}],
+      }, {
+        recordTrace: true,
+        passName: 'secondPass',
+        gatherers: [{instance: new TestGatherer()}],
+      }],
+    });
+    const options = {
+      driver: fakeDriver,
+      requestedUrl: 'https://example.com',
+      settings: config.settings,
+    };
 
-    return GatherRunner.run(passes, options)
+    return GatherRunner.run(config.passes, options)
       .then(artifacts => {
         assert.ok(artifacts.traces.firstPass);
         assert.ok(artifacts.devtoolsLogs.firstPass);
@@ -759,23 +765,108 @@ describe('GatherRunner', function() {
   });
 
   it('doesn\'t leave networkRecords as an artifact', () => {
-    const passes = [{
-      recordTrace: true,
-      passName: 'firstPass',
-      gatherers: [{instance: new TestGatherer()}],
-    }, {
-      recordTrace: true,
-      passName: 'secondPass',
-      gatherers: [{instance: new TestGatherer()}],
-    }];
-    const options = {driver: fakeDriver, requestedUrl: 'https://example.com', settings: {}, config: {}};
+    const config = new Config({
+      passes: [{
+        recordTrace: true,
+        passName: 'firstPass',
+        gatherers: [{instance: new TestGatherer()}],
+      }, {
+        recordTrace: true,
+        passName: 'secondPass',
+        gatherers: [{instance: new TestGatherer()}],
+      }],
+    });
+    const options = {
+      driver: fakeDriver,
+      requestedUrl: 'https://example.com',
+      settings: config.settings,
+    };
 
-    return GatherRunner.run(passes, options)
+    return GatherRunner.run(config.passes, options)
       .then(artifacts => {
         assert.equal(artifacts.networkRecords, undefined);
       });
   });
 
+  it('saves trace and devtoolsLog with error prefix when there was a runtime error', async () => {
+    const requestedUrl = 'https://example.com';
+    const driver = Object.assign({}, fakeDriver, {
+      // resolved URL here does not match any request in the network records, causing a runtime error.
+      gotoURL: async _ => requestedUrl,
+      online: true,
+    });
+
+    const config = new Config({
+      passes: [{
+        passName: 'firstPass',
+        recordTrace: true,
+        gatherers: [{instance: new TestGatherer()}],
+      }],
+    });
+    const options = {driver, requestedUrl, settings: config.settings};
+    const artifacts = await GatherRunner.run(config.passes, options);
+
+    expect(artifacts.TestGatherer.code).toEqual('NO_DOCUMENT_REQUEST');
+
+    // The only loadData available should be prefixed with `pageLoadError-`.
+    expect(Object.keys(artifacts.traces)).toEqual(['pageLoadError-firstPass']);
+    expect(Object.keys(artifacts.devtoolsLogs)).toEqual(['pageLoadError-firstPass']);
+  });
+
+  it('does not run additional passes after a runtime error', async () => {
+    const t1 = new (class Test1 extends TestGatherer {})();
+    const t2 = new (class Test2 extends TestGatherer {})();
+    const t3 = new (class Test3 extends TestGatherer {})();
+    const config = new Config({
+      passes: [{
+        passName: 'firstPass',
+        recordTrace: true,
+        gatherers: [{instance: t1}],
+      }, {
+        passName: 'secondPass',
+        recordTrace: true,
+        gatherers: [{instance: t2}],
+      }, {
+        passName: 'thirdPass',
+        recordTrace: true,
+        gatherers: [{instance: t3}],
+      }],
+    });
+
+    const requestedUrl = 'https://www.reddit.com/r/nba';
+    let firstLoad = true;
+    const driver = Object.assign({}, fakeDriver, {
+      // Loads the page successfully in the first pass, fails with NO_FCP in the second.
+      async gotoURL(url) {
+        if (url.includes('blank')) return null;
+        if (firstLoad) {
+          firstLoad = false;
+          return requestedUrl;
+        } else {
+          throw new LHError(LHError.errors.NO_FCP);
+        }
+      },
+      online: true,
+    });
+    const options = {driver, requestedUrl, settings: config.settings};
+    const artifacts = await GatherRunner.run(config.passes, options);
+
+    // t1.pass() and t2.pass() called; t3.pass(), after the error, was not.
+    expect(t1.called).toBe(true);
+    expect(t2.called).toBe(true);
+    expect(t3.called).toBe(false);
+
+    // But only t1 has a valid artifact, t2 has an error artifact, and t3 never ran.
+    expect(artifacts.Test1).toBe('MyArtifact');
+    expect(artifacts.Test2).toBeInstanceOf(LHError);
+    expect(artifacts.Test2.code).toEqual('NO_FCP');
+    expect(artifacts.Test3).toBeUndefined();
+
+    // firstPass has a saved trace and devtoolsLog, secondPass has an error trace and log.
+    expect(Object.keys(artifacts.traces)).toEqual(['firstPass', 'pageLoadError-secondPass']);
+    expect(Object.keys(artifacts.devtoolsLogs)).toEqual(['firstPass', 'pageLoadError-secondPass']);
+  });
+
   describe('#getNetworkError', () => {
     it('passes when the page is loaded', () => {
       const url = 'http://the-page.com';
@@ -1043,15 +1134,16 @@ describe('GatherRunner', function() {
           }
         },
       ];
-      const passes = [{
-
-        gatherers: gatherers.map(G => ({instance: new G()})),
-      }];
+      const config = new Config({
+        passes: [{
+          gatherers: gatherers.map(G => ({instance: new G()})),
+        }],
+      });
 
-      const artifacts = await GatherRunner.run(passes, {
+      const artifacts = await GatherRunner.run(config.passes, {
         driver: fakeDriver,
         requestedUrl: 'https://example.com',
-        settings: {},
+        settings: config.settings,
       });
 
       // Ensure artifacts returned and not errors.
@@ -1097,16 +1189,16 @@ describe('GatherRunner', function() {
         }(),
       ].map(instance => ({instance}));
       const gathererNames = gatherers.map(gatherer => gatherer.instance.name);
-      const passes = [{
-
-        gatherers,
-      }];
+      const config = new Config({
+        passes: [{
+          gatherers,
+        }],
+      });
 
-      return GatherRunner.run(passes, {
+      return GatherRunner.run(config.passes, {
         driver: fakeDriver,
         requestedUrl: 'https://example.com',
-        settings: {},
-        config: new Config({}),
+        settings: config.settings,
       }).then(artifacts => {
         gathererNames.forEach(gathererName => {
           assert.strictEqual(artifacts[gathererName], gathererName);
@@ -1135,12 +1227,14 @@ describe('GatherRunner', function() {
         {instance: new class EavesdropGatherer3 extends EavesdropGatherer {}()},
       ];
 
-      const passes = [{gatherers}];
-      return GatherRunner.run(passes, {
+      const config = new Config({
+        passes: [{gatherers}],
+      });
+
+      return GatherRunner.run(config.passes, {
         driver: fakeDriver,
         requestedUrl: 'https://example.com',
-        settings: {},
-        config: new Config({}),
+        settings: config.settings,
       }).then(artifacts => {
         assert.equal(artifacts.EavesdropGatherer1, 1);
         assert.equal(artifacts.EavesdropGatherer2, 2);
@@ -1191,7 +1285,7 @@ describe('GatherRunner', function() {
         ],
       };
 
-      return GatherRunner.collectArtifacts(gathererResults, {}).then(({artifacts}) => {
+      return GatherRunner.collectArtifacts(gathererResults).then(({artifacts}) => {
         assert.strictEqual(artifacts.AfterGatherer, 97);
         assert.strictEqual(artifacts.PassGatherer, 284);
         assert.strictEqual(artifacts.SingleErrorGatherer, recoverableError);
@@ -1215,14 +1309,15 @@ describe('GatherRunner', function() {
         }
       }
 
-      const passes = [{
-        gatherers: [{instance: new WarningGatherer()}],
-      }];
-      const artifacts = await GatherRunner.run(passes, {
+      const config = new Config({
+        passes: [{
+          gatherers: [{instance: new WarningGatherer()}],
+        }],
+      });
+      const artifacts = await GatherRunner.run(config.passes, {
         driver: fakeDriver,
         requestedUrl: 'https://example.com',
-        settings: {},
-        config: new Config({}),
+        settings: config.settings,
       });
       assert.deepStrictEqual(artifacts.LighthouseRunWarnings, runWarnings);
     });
@@ -1267,16 +1362,16 @@ describe('GatherRunner', function() {
         }(),
       ].map(instance => ({instance}));
       const gathererNames = gatherers.map(gatherer => gatherer.instance.name);
-      const passes = [{
-
-        gatherers,
-      }];
+      const config = new Config({
+        passes: [{
+          gatherers,
+        }],
+      });
 
-      return GatherRunner.run(passes, {
+      return GatherRunner.run(config.passes, {
         driver: fakeDriver,
         requestedUrl: 'https://example.com',
-        settings: {},
-        config: new Config({}),
+        settings: config.settings,
       }).then(artifacts => {
         gathererNames.forEach(gathererName => {
           const errorArtifact = artifacts[gathererName];
@@ -1287,48 +1382,48 @@ describe('GatherRunner', function() {
     });
 
     it('rejects if a gatherer does not provide an artifact', () => {
-      const passes = [{
-
-        recordTrace: true,
-        passName: 'firstPass',
-        gatherers: [
-          {instance: new TestGathererNoArtifact()},
-        ],
-      }];
+      const config = new Config({
+        passes: [{
+          recordTrace: true,
+          passName: 'firstPass',
+          gatherers: [
+            {instance: new TestGathererNoArtifact()},
+          ],
+        }],
+      });
 
-      return GatherRunner.run(passes, {
+      return GatherRunner.run(config.passes, {
         driver: fakeDriver,
         requestedUrl: 'https://example.com',
-        settings: {},
-        config: new Config({}),
+        settings: config.settings,
       }).then(_ => assert.ok(false), _ => assert.ok(true));
     });
 
     it('rejects when domain name can\'t be resolved', () => {
-      const passes = [{
-
-        recordTrace: true,
-        passName: 'firstPass',
-        gatherers: [],
-      }];
+      const config = new Config({
+        passes: [{
+          recordTrace: true,
+          passName: 'firstPass',
+          gatherers: [],
+        }],
+      });
 
       // Arrange for driver to return unresolved request.
-      const url = 'http://www.some-non-existing-domain.com/';
+      const requestedUrl = 'http://www.some-non-existing-domain.com/';
       const unresolvedDriver = Object.assign({}, fakeDriver, {
         online: true,
         gotoURL() {
-          return Promise.resolve(url);
+          return Promise.resolve(requestedUrl);
         },
         endDevtoolsLog() {
           return unresolvedPerfLog;
         },
       });
 
-      return GatherRunner.run(passes, {
+      return GatherRunner.run(config.passes, {
         driver: unresolvedDriver,
-        url,
-        settings: {},
-        config: new Config({}),
+        requestedUrl,
+        settings: config.settings,
       }).then(artifacts => {
         assert.equal(artifacts.LighthouseRunWarnings.length, 1);
         expect(artifacts.LighthouseRunWarnings[0])
@@ -1337,30 +1432,30 @@ describe('GatherRunner', function() {
     });
 
     it('resolves when domain name can\'t be resolved but is offline', () => {
-      const passes = [{
-
-        recordTrace: true,
-        passName: 'firstPass',
-        gatherers: [],
-      }];
+      const config = new Config({
+        passes: [{
+          recordTrace: true,
+          passName: 'firstPass',
+          gatherers: [],
+        }],
+      });
 
       // Arrange for driver to return unresolved request.
-      const url = 'http://www.some-non-existing-domain.com/';
+      const requestedUrl = 'http://www.some-non-existing-domain.com/';
       const unresolvedDriver = Object.assign({}, fakeDriver, {
         online: false,
         gotoURL() {
-          return Promise.resolve(url);
+          return Promise.resolve(requestedUrl);
         },
         endDevtoolsLog() {
           return unresolvedPerfLog;
         },
       });
 
-      return GatherRunner.run(passes, {
+      return GatherRunner.run(config.passes, {
         driver: unresolvedDriver,
-        url,
-        settings: {},
-        config: new Config({}),
+        requestedUrl,
+        settings: config.settings,
       })
         .then(_ => {
           assert.ok(true);