lighthouse 9.5.0-dev.20220514 → 9.5.0-dev.20220517

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1586,7 +1586,7 @@ class DOM {
1586
1586
  */
1587
1587
  createChildOf(parentElem, elementName, className) {
1588
1588
  const element = this.createElement(elementName, className);
1589
- parentElem.appendChild(element);
1589
+ parentElem.append(element);
1590
1590
  return element;
1591
1591
  }
1592
1592
 
@@ -1624,7 +1624,7 @@ class DOM {
1624
1624
  for (const segment of Util.splitMarkdownLink(text)) {
1625
1625
  if (!segment.isLink) {
1626
1626
  // Plain text segment.
1627
- element.appendChild(this._document.createTextNode(segment.text));
1627
+ element.append(this._document.createTextNode(segment.text));
1628
1628
  continue;
1629
1629
  }
1630
1630
 
@@ -1642,7 +1642,7 @@ class DOM {
1642
1642
  a.target = '_blank';
1643
1643
  a.textContent = segment.text;
1644
1644
  this.safelySetHref(a, url.href);
1645
- element.appendChild(a);
1645
+ element.append(a);
1646
1646
  }
1647
1647
 
1648
1648
  return element;
@@ -1699,9 +1699,9 @@ class DOM {
1699
1699
  if (segment.isCode) {
1700
1700
  const pre = this.createElement('code');
1701
1701
  pre.textContent = segment.text;
1702
- element.appendChild(pre);
1702
+ element.append(pre);
1703
1703
  } else {
1704
- element.appendChild(this._document.createTextNode(segment.text));
1704
+ element.append(this._document.createTextNode(segment.text));
1705
1705
  }
1706
1706
  }
1707
1707
 
@@ -1784,7 +1784,7 @@ class DOM {
1784
1784
  const a = this.createElement('a');
1785
1785
  a.download = filename;
1786
1786
  this.safelySetBlobHref(a, blob);
1787
- this._document.body.appendChild(a); // Firefox requires anchor to be in the DOM.
1787
+ this._document.body.append(a); // Firefox requires anchor to be in the DOM.
1788
1788
  a.click();
1789
1789
 
1790
1790
  // cleanup.
@@ -1860,9 +1860,9 @@ class CategoryRenderer {
1860
1860
  }
1861
1861
 
1862
1862
  const titleEl = this.dom.find('.lh-audit__title', auditEl);
1863
- titleEl.appendChild(this.dom.convertMarkdownCodeSnippets(audit.result.title));
1863
+ titleEl.append(this.dom.convertMarkdownCodeSnippets(audit.result.title));
1864
1864
  const descEl = this.dom.find('.lh-audit__description', auditEl);
1865
- descEl.appendChild(this.dom.convertMarkdownLinkSnippets(audit.result.description));
1865
+ descEl.append(this.dom.convertMarkdownLinkSnippets(audit.result.description));
1866
1866
 
1867
1867
  for (const relevantMetric of audit.relevantMetrics || []) {
1868
1868
  const adornEl = this.dom.createChildOf(descEl, 'span', 'lh-audit__adorn');
@@ -1872,19 +1872,16 @@ class CategoryRenderer {
1872
1872
 
1873
1873
  if (audit.stackPacks) {
1874
1874
  audit.stackPacks.forEach(pack => {
1875
- const packElm = this.dom.createElement('div');
1876
- packElm.classList.add('lh-audit__stackpack');
1877
-
1878
- const packElmImg = this.dom.createElement('img');
1879
- packElmImg.classList.add('lh-audit__stackpack__img');
1875
+ const packElmImg = this.dom.createElement('img', 'lh-audit__stackpack__img');
1880
1876
  packElmImg.src = pack.iconDataURL;
1881
1877
  packElmImg.alt = pack.title;
1882
- packElm.appendChild(packElmImg);
1883
1878
 
1884
- packElm.appendChild(this.dom.convertMarkdownLinkSnippets(pack.description));
1879
+ const snippets = this.dom.convertMarkdownLinkSnippets(pack.description);
1880
+ const packElm = this.dom.createElement('div', 'lh-audit__stackpack');
1881
+ packElm.append(packElmImg, snippets);
1885
1882
 
1886
1883
  this.dom.find('.lh-audit__stackpacks', auditEl)
1887
- .appendChild(packElm);
1884
+ .append(packElm);
1888
1885
  });
1889
1886
  }
1890
1887
 
@@ -1893,12 +1890,12 @@ class CategoryRenderer {
1893
1890
  const elem = this.detailsRenderer.render(audit.result.details);
1894
1891
  if (elem) {
1895
1892
  elem.classList.add('lh-details');
1896
- header.appendChild(elem);
1893
+ header.append(elem);
1897
1894
  }
1898
1895
  }
1899
1896
 
1900
1897
  // Add chevron SVG to the end of the summary
1901
- this.dom.find('.lh-chevron-container', auditEl).appendChild(this._createChevron());
1898
+ this.dom.find('.lh-chevron-container', auditEl).append(this._createChevron());
1902
1899
  this._setRatingClass(auditEl, audit.result.score, scoreDisplayMode);
1903
1900
 
1904
1901
  if (audit.result.scoreDisplayMode === 'error') {
@@ -1920,7 +1917,7 @@ class CategoryRenderer {
1920
1917
  const warningsEl = this.dom.createChildOf(summaryEl, 'div', 'lh-warnings');
1921
1918
  this.dom.createChildOf(warningsEl, 'span').textContent = strings.warningHeader;
1922
1919
  if (warnings.length === 1) {
1923
- warningsEl.appendChild(this.dom.createTextNode(warnings.join('')));
1920
+ warningsEl.append(this.dom.createTextNode(warnings.join('')));
1924
1921
  } else {
1925
1922
  const warningsUl = this.dom.createChildOf(warningsEl, 'ul');
1926
1923
  for (const warning of warnings) {
@@ -1995,11 +1992,11 @@ class CategoryRenderer {
1995
1992
 
1996
1993
  const gaugeContainerEl = this.dom.find('.lh-score__gauge', component);
1997
1994
  const gaugeEl = this.renderCategoryScore(category, groupDefinitions, options);
1998
- gaugeContainerEl.appendChild(gaugeEl);
1995
+ gaugeContainerEl.append(gaugeEl);
1999
1996
 
2000
1997
  if (category.description) {
2001
1998
  const descEl = this.dom.convertMarkdownLinkSnippets(category.description);
2002
- this.dom.find('.lh-category-header__description', component).appendChild(descEl);
1999
+ this.dom.find('.lh-category-header__description', component).append(descEl);
2003
2000
  }
2004
2001
 
2005
2002
  return component;
@@ -2018,13 +2015,13 @@ class CategoryRenderer {
2018
2015
 
2019
2016
  this.dom.createChildOf(auditGroupHeader, 'span', 'lh-audit-group__title')
2020
2017
  .textContent = group.title;
2021
- groupEl.appendChild(auditGroupHeader);
2018
+ groupEl.append(auditGroupHeader);
2022
2019
 
2023
2020
  let footerEl = null;
2024
2021
  if (group.description) {
2025
2022
  footerEl = this.dom.convertMarkdownLinkSnippets(group.description);
2026
2023
  footerEl.classList.add('lh-audit-group__description', 'lh-audit-group__footer');
2027
- groupEl.appendChild(footerEl);
2024
+ groupEl.append(footerEl);
2028
2025
  }
2029
2026
 
2030
2027
  return [groupEl, footerEl];
@@ -2088,7 +2085,7 @@ class CategoryRenderer {
2088
2085
  renderUnexpandableClump(auditRefs, groupDefinitions) {
2089
2086
  const clumpElement = this.dom.createElement('div');
2090
2087
  const elements = this._renderGroupedAudits(auditRefs, groupDefinitions);
2091
- elements.forEach(elem => clumpElement.appendChild(elem));
2088
+ elements.forEach(elem => clumpElement.append(elem));
2092
2089
  return clumpElement;
2093
2090
  }
2094
2091
 
@@ -2122,7 +2119,7 @@ class CategoryRenderer {
2122
2119
  if (description) {
2123
2120
  const descriptionEl = this.dom.convertMarkdownLinkSnippets(description);
2124
2121
  descriptionEl.classList.add('lh-audit-group__description', 'lh-audit-group__footer');
2125
- el.appendChild(descriptionEl);
2122
+ el.append(descriptionEl);
2126
2123
  }
2127
2124
 
2128
2125
  this.dom.find('.lh-clump-toggletext--show', el).textContent = Util.i18n.strings.show;
@@ -2214,7 +2211,7 @@ class CategoryRenderer {
2214
2211
  const content = this.dom.find('.lh-fraction__content', tmpl);
2215
2212
  const text = this.dom.createElement('span');
2216
2213
  text.textContent = `${numPassed}/${numPassableAudits}`;
2217
- content.appendChild(text);
2214
+ content.append(text);
2218
2215
 
2219
2216
  let rating = Util.calculateRating(fraction);
2220
2217
 
@@ -2318,7 +2315,7 @@ class CategoryRenderer {
2318
2315
  render(category, groupDefinitions = {}, options) {
2319
2316
  const element = this.dom.createElement('div', 'lh-category');
2320
2317
  element.id = category.id;
2321
- element.appendChild(this.renderCategoryHeader(category, groupDefinitions, options));
2318
+ element.append(this.renderCategoryHeader(category, groupDefinitions, options));
2322
2319
 
2323
2320
  // Top level clumps for audits, in order they will appear in the report.
2324
2321
  /** @type {Map<TopLevelClumpId, Array<LH.ReportResult.AuditRef>>} */
@@ -2351,13 +2348,13 @@ class CategoryRenderer {
2351
2348
  if (clumpId === 'failed') {
2352
2349
  const clumpElem = this.renderUnexpandableClump(auditRefs, groupDefinitions);
2353
2350
  clumpElem.classList.add(`lh-clump--failed`);
2354
- element.appendChild(clumpElem);
2351
+ element.append(clumpElem);
2355
2352
  continue;
2356
2353
  }
2357
2354
 
2358
2355
  const description = clumpId === 'manual' ? category.manualDescription : undefined;
2359
2356
  const clumpElem = this.renderClump(clumpId, {auditRefs, description});
2360
- element.appendChild(clumpElem);
2357
+ element.append(clumpElem);
2361
2358
  }
2362
2359
 
2363
2360
  return element;
@@ -2464,34 +2461,33 @@ class CriticalRequestChainRenderer {
2464
2461
 
2465
2462
  // Construct lines and add spacers for sub requests.
2466
2463
  segment.treeMarkers.forEach(separator => {
2467
- if (separator) {
2468
- treeMarkeEl.appendChild(dom.createElement('span', 'lh-tree-marker lh-vert'));
2469
- treeMarkeEl.appendChild(dom.createElement('span', 'lh-tree-marker'));
2470
- } else {
2471
- treeMarkeEl.appendChild(dom.createElement('span', 'lh-tree-marker'));
2472
- treeMarkeEl.appendChild(dom.createElement('span', 'lh-tree-marker'));
2473
- }
2464
+ const classSeparator = separator ?
2465
+ 'lh-tree-marker lh-vert' :
2466
+ 'lh-tree-marker';
2467
+ treeMarkeEl.append(
2468
+ dom.createElement('span', classSeparator),
2469
+ dom.createElement('span', 'lh-tree-marker')
2470
+ );
2474
2471
  });
2475
2472
 
2476
- if (segment.isLastChild) {
2477
- treeMarkeEl.appendChild(dom.createElement('span', 'lh-tree-marker lh-up-right'));
2478
- treeMarkeEl.appendChild(dom.createElement('span', 'lh-tree-marker lh-right'));
2479
- } else {
2480
- treeMarkeEl.appendChild(dom.createElement('span', 'lh-tree-marker lh-vert-right'));
2481
- treeMarkeEl.appendChild(dom.createElement('span', 'lh-tree-marker lh-right'));
2482
- }
2483
-
2484
- if (segment.hasChildren) {
2485
- treeMarkeEl.appendChild(dom.createElement('span', 'lh-tree-marker lh-horiz-down'));
2486
- } else {
2487
- treeMarkeEl.appendChild(dom.createElement('span', 'lh-tree-marker lh-right'));
2488
- }
2473
+ const classLastChild = segment.isLastChild ?
2474
+ 'lh-tree-marker lh-up-right' :
2475
+ 'lh-tree-marker lh-vert-right';
2476
+ const classHasChildren = segment.hasChildren ?
2477
+ 'lh-tree-marker lh-horiz-down' :
2478
+ 'lh-tree-marker lh-right';
2479
+
2480
+ treeMarkeEl.append(
2481
+ dom.createElement('span', classLastChild),
2482
+ dom.createElement('span', 'lh-tree-marker lh-right'),
2483
+ dom.createElement('span', classHasChildren)
2484
+ );
2489
2485
 
2490
2486
  // Fill in url, host, and request size information.
2491
2487
  const url = segment.node.request.url;
2492
2488
  const linkEl = detailsRenderer.renderTextURL(url);
2493
2489
  const treevalEl = dom.find('.lh-crc-node__tree-value', chainEl);
2494
- treevalEl.appendChild(linkEl);
2490
+ treevalEl.append(linkEl);
2495
2491
 
2496
2492
  if (!segment.hasChildren) {
2497
2493
  const {startTime, endTime, transferSize} = segment.node.request;
@@ -2500,8 +2496,7 @@ class CriticalRequestChainRenderer {
2500
2496
  const span2 = dom.createElement('span', 'lh-crc-node__chain-duration');
2501
2497
  span2.textContent = Util.i18n.formatBytesToKiB(transferSize, 0.01);
2502
2498
 
2503
- treevalEl.appendChild(span);
2504
- treevalEl.appendChild(span2);
2499
+ treevalEl.append(span, span2);
2505
2500
  }
2506
2501
 
2507
2502
  return chainEl;
@@ -2517,7 +2512,7 @@ class CriticalRequestChainRenderer {
2517
2512
  * @param {DetailsRenderer} detailsRenderer
2518
2513
  */
2519
2514
  static buildTree(dom, tmpl, segment, elem, details, detailsRenderer) {
2520
- elem.appendChild(CRCRenderer.createChainNode(dom, segment, detailsRenderer));
2515
+ elem.append(CRCRenderer.createChainNode(dom, segment, detailsRenderer));
2521
2516
  if (segment.node.children) {
2522
2517
  for (const key of Object.keys(segment.node.children)) {
2523
2518
  const childSegment = CRCRenderer.createSegment(segment.node.children, key,
@@ -2726,7 +2721,7 @@ class ElementScreenshotRenderer {
2726
2721
  overlay.remove();
2727
2722
  return;
2728
2723
  }
2729
- overlay.appendChild(screenshotElement);
2724
+ overlay.append(screenshotElement);
2730
2725
  overlay.addEventListener('click', () => overlay.remove());
2731
2726
  });
2732
2727
  }
@@ -2931,12 +2926,12 @@ class DetailsRenderer {
2931
2926
  }
2932
2927
 
2933
2928
  const element = this._dom.createElement('div', 'lh-text__url');
2934
- element.appendChild(this._renderLink({text: displayedPath, url}));
2929
+ element.append(this._renderLink({text: displayedPath, url}));
2935
2930
 
2936
2931
  if (displayedHost) {
2937
2932
  const hostElem = this._renderText(displayedHost);
2938
2933
  hostElem.classList.add('lh-text__url-host');
2939
- element.appendChild(hostElem);
2934
+ element.append(hostElem);
2940
2935
  }
2941
2936
 
2942
2937
  if (title) {
@@ -3209,7 +3204,7 @@ class DetailsRenderer {
3209
3204
 
3210
3205
  if (valueElement) {
3211
3206
  const classes = `lh-table-column--${heading.valueType}`;
3212
- this._dom.createChildOf(rowElem, 'td', classes).appendChild(valueElement);
3207
+ this._dom.createChildOf(rowElem, 'td', classes).append(valueElement);
3213
3208
  } else {
3214
3209
  // Empty cell is rendered for a column if:
3215
3210
  // - the pair is null
@@ -3264,7 +3259,7 @@ class DetailsRenderer {
3264
3259
  const classes = `lh-table-column--${valueType}`;
3265
3260
  const labelEl = this._dom.createElement('div', 'lh-text');
3266
3261
  labelEl.textContent = heading.label;
3267
- this._dom.createChildOf(theadTrElem, 'th', classes).appendChild(labelEl);
3262
+ this._dom.createChildOf(theadTrElem, 'th', classes).append(labelEl);
3268
3263
  }
3269
3264
 
3270
3265
  const tbodyElem = this._dom.createChildOf(tableElem, 'tbody');
@@ -3307,13 +3302,13 @@ class DetailsRenderer {
3307
3302
  if (item.nodeLabel) {
3308
3303
  const nodeLabelEl = this._dom.createElement('div');
3309
3304
  nodeLabelEl.textContent = item.nodeLabel;
3310
- element.appendChild(nodeLabelEl);
3305
+ element.append(nodeLabelEl);
3311
3306
  }
3312
3307
  if (item.snippet) {
3313
3308
  const snippetEl = this._dom.createElement('div');
3314
3309
  snippetEl.classList.add('lh-node__snippet');
3315
3310
  snippetEl.textContent = item.snippet;
3316
- element.appendChild(snippetEl);
3311
+ element.append(snippetEl);
3317
3312
  }
3318
3313
  if (item.selector) {
3319
3314
  element.title = item.selector;
@@ -3704,7 +3699,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
3704
3699
  valueEl.textContent = audit.result.displayValue || '';
3705
3700
 
3706
3701
  const descriptionEl = this.dom.find('.lh-metric__description', tmpl);
3707
- descriptionEl.appendChild(this.dom.convertMarkdownLinkSnippets(audit.result.description));
3702
+ descriptionEl.append(this.dom.convertMarkdownLinkSnippets(audit.result.description));
3708
3703
 
3709
3704
  if (audit.result.scoreDisplayMode === 'error') {
3710
3705
  descriptionEl.textContent = '';
@@ -3844,7 +3839,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
3844
3839
  const strings = Util.i18n.strings;
3845
3840
  const element = this.dom.createElement('div', 'lh-category');
3846
3841
  element.id = category.id;
3847
- element.appendChild(this.renderCategoryHeader(category, groups, options));
3842
+ element.append(this.renderCategoryHeader(category, groups, options));
3848
3843
 
3849
3844
  // Metrics.
3850
3845
  const metricAudits = category.auditRefs.filter(audit => audit.group === 'metrics');
@@ -3869,7 +3864,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
3869
3864
  const metricsBoxesEl = this.dom.createElement('div', 'lh-metrics-container');
3870
3865
  metricsGroupEl.insertBefore(metricsBoxesEl, metricsFooterEl);
3871
3866
  metricAudits.forEach(item => {
3872
- metricsBoxesEl.appendChild(this._renderMetric(item));
3867
+ metricsBoxesEl.append(this._renderMetric(item));
3873
3868
  });
3874
3869
 
3875
3870
  // Only add the disclaimer with the score calculator link if the category was rendered with a score gauge.
@@ -3877,7 +3872,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
3877
3872
  const descriptionEl = this.dom.find('.lh-category-header__description', element);
3878
3873
  const estValuesEl = this.dom.createChildOf(descriptionEl, 'div', 'lh-metrics__disclaimer');
3879
3874
  const disclaimerEl = this.dom.convertMarkdownLinkSnippets(strings.varianceDisclaimer);
3880
- estValuesEl.appendChild(disclaimerEl);
3875
+ estValuesEl.append(disclaimerEl);
3881
3876
 
3882
3877
  // Add link to score calculator.
3883
3878
  const calculatorLink = this.dom.createChildOf(estValuesEl, 'a', 'lh-calclink');
@@ -3887,7 +3882,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
3887
3882
  }
3888
3883
 
3889
3884
  metricsGroupEl.classList.add('lh-audit-group--metrics');
3890
- element.appendChild(metricsGroupEl);
3885
+ element.append(metricsGroupEl);
3891
3886
  }
3892
3887
 
3893
3888
  // Filmstrip
@@ -3897,7 +3892,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
3897
3892
  if (thumbnailResult?.details) {
3898
3893
  timelineEl.id = thumbnailResult.id;
3899
3894
  const filmstripEl = this.detailsRenderer.render(thumbnailResult.details);
3900
- filmstripEl && timelineEl.appendChild(filmstripEl);
3895
+ filmstripEl && timelineEl.append(filmstripEl);
3901
3896
  }
3902
3897
 
3903
3898
  // Opportunities
@@ -3931,7 +3926,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
3931
3926
  opportunityAudits.forEach(item =>
3932
3927
  groupEl.insertBefore(this._renderOpportunity(item, scale), footerEl));
3933
3928
  groupEl.classList.add('lh-audit-group--load-opportunities');
3934
- element.appendChild(groupEl);
3929
+ element.append(groupEl);
3935
3930
  }
3936
3931
 
3937
3932
  // Diagnostics
@@ -3948,7 +3943,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
3948
3943
  const [groupEl, footerEl] = this.renderAuditGroup(groups['diagnostics']);
3949
3944
  diagnosticAudits.forEach(item => groupEl.insertBefore(this.renderAudit(item), footerEl));
3950
3945
  groupEl.classList.add('lh-audit-group--diagnostics');
3951
- element.appendChild(groupEl);
3946
+ element.append(groupEl);
3952
3947
  }
3953
3948
 
3954
3949
  // Passed audits
@@ -3962,7 +3957,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
3962
3957
  groupDefinitions: groups,
3963
3958
  };
3964
3959
  const passedElem = this.renderClump('passed', clumpOpts);
3965
- element.appendChild(passedElem);
3960
+ element.append(passedElem);
3966
3961
 
3967
3962
  // Budgets
3968
3963
  /** @type {Array<Element>} */
@@ -3982,7 +3977,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
3982
3977
  const [groupEl, footerEl] = this.renderAuditGroup(groups.budgets);
3983
3978
  budgetTableEls.forEach(table => groupEl.insertBefore(table, footerEl));
3984
3979
  groupEl.classList.add('lh-audit-group--budgets');
3985
- element.appendChild(groupEl);
3980
+ element.append(groupEl);
3986
3981
  }
3987
3982
 
3988
3983
  return element;
@@ -4082,7 +4077,7 @@ class PwaCategoryRenderer extends CategoryRenderer {
4082
4077
  render(category, groupDefinitions = {}) {
4083
4078
  const categoryElem = this.dom.createElement('div', 'lh-category');
4084
4079
  categoryElem.id = category.id;
4085
- categoryElem.appendChild(this.renderCategoryHeader(category, groupDefinitions));
4080
+ categoryElem.append(this.renderCategoryHeader(category, groupDefinitions));
4086
4081
 
4087
4082
  const auditRefs = category.auditRefs;
4088
4083
 
@@ -4090,13 +4085,13 @@ class PwaCategoryRenderer extends CategoryRenderer {
4090
4085
  // all put in a top-level clump that isn't expandable/collapsible.
4091
4086
  const regularAuditRefs = auditRefs.filter(ref => ref.result.scoreDisplayMode !== 'manual');
4092
4087
  const auditsElem = this._renderAudits(regularAuditRefs, groupDefinitions);
4093
- categoryElem.appendChild(auditsElem);
4088
+ categoryElem.append(auditsElem);
4094
4089
 
4095
4090
  // Manual audits are still in a manual clump.
4096
4091
  const manualAuditRefs = auditRefs.filter(ref => ref.result.scoreDisplayMode === 'manual');
4097
4092
  const manualElem = this.renderClump('manual',
4098
4093
  {auditRefs: manualAuditRefs, description: category.manualDescription});
4099
- categoryElem.appendChild(manualElem);
4094
+ categoryElem.append(manualElem);
4100
4095
 
4101
4096
  return categoryElem;
4102
4097
  }
@@ -4301,7 +4296,7 @@ class ReportRenderer {
4301
4296
  const report = Util.prepareReportResult(lhr);
4302
4297
 
4303
4298
  this._dom.rootEl.textContent = ''; // Remove previous report.
4304
- this._dom.rootEl.appendChild(this._renderReport(report));
4299
+ this._dom.rootEl.append(this._renderReport(report));
4305
4300
 
4306
4301
  return this._dom.rootEl;
4307
4302
  }
@@ -4409,11 +4404,13 @@ class ReportRenderer {
4409
4404
  const message = this._dom.find('.lh-warnings__msg', container);
4410
4405
  message.textContent = Util.i18n.strings.toplevelWarningsMessage;
4411
4406
 
4412
- const warnings = this._dom.find('ul', container);
4407
+ const warnings = [];
4413
4408
  for (const warningString of report.runWarnings) {
4414
- const warning = warnings.appendChild(this._dom.createElement('li'));
4415
- warning.appendChild(this._dom.convertMarkdownLinkSnippets(warningString));
4409
+ const warning = this._dom.createElement('li');
4410
+ warning.append(this._dom.convertMarkdownLinkSnippets(warningString));
4411
+ warnings.push(warning);
4416
4412
  }
4413
+ this._dom.find('ul', container).append(...warnings);
4417
4414
 
4418
4415
  return container;
4419
4416
  }
@@ -4506,11 +4503,11 @@ class ReportRenderer {
4506
4503
  };
4507
4504
 
4508
4505
  const headerContainer = this._dom.createElement('div');
4509
- headerContainer.appendChild(this._renderReportHeader());
4506
+ headerContainer.append(this._renderReportHeader());
4510
4507
 
4511
4508
  const reportContainer = this._dom.createElement('div', 'lh-container');
4512
4509
  const reportSection = this._dom.createElement('div', 'lh-report');
4513
- reportSection.appendChild(this._renderReportWarnings(report));
4510
+ reportSection.append(this._renderReportWarnings(report));
4514
4511
 
4515
4512
  let scoreHeader;
4516
4513
  const isSoloCategory = Object.keys(report.categories).length === 1;
@@ -4527,23 +4524,23 @@ class ReportRenderer {
4527
4524
  const scoresContainer = this._dom.find('.lh-scores-container', headerContainer);
4528
4525
  scoreHeader.append(
4529
4526
  ...this._renderScoreGauges(report, categoryRenderer, specificCategoryRenderers));
4530
- scoresContainer.appendChild(scoreHeader);
4531
- scoresContainer.appendChild(scoreScale);
4527
+ scoresContainer.append(scoreHeader, scoreScale);
4532
4528
 
4533
4529
  const stickyHeader = this._dom.createElement('div', 'lh-sticky-header');
4534
4530
  stickyHeader.append(
4535
4531
  ...this._renderScoreGauges(report, categoryRenderer, specificCategoryRenderers));
4536
- reportContainer.appendChild(stickyHeader);
4532
+ reportContainer.append(stickyHeader);
4537
4533
  }
4538
4534
 
4539
- const categories = reportSection.appendChild(this._dom.createElement('div', 'lh-categories'));
4535
+ const categories = this._dom.createElement('div', 'lh-categories');
4536
+ reportSection.append(categories);
4540
4537
  const categoryOptions = {gatherMode: report.gatherMode};
4541
4538
  for (const category of Object.values(report.categories)) {
4542
4539
  const renderer = specificCategoryRenderers[category.id] || categoryRenderer;
4543
4540
  // .lh-category-wrapper is full-width and provides horizontal rules between categories.
4544
4541
  // .lh-category within has the max-width: var(--report-content-max-width);
4545
4542
  const wrapper = renderer.dom.createChildOf(categories, 'div', 'lh-category-wrapper');
4546
- wrapper.appendChild(renderer.render(
4543
+ wrapper.append(renderer.render(
4547
4544
  category,
4548
4545
  report.categoryGroups,
4549
4546
  categoryOptions
@@ -4558,13 +4555,12 @@ class ReportRenderer {
4558
4555
  }
4559
4556
 
4560
4557
  if (!this._opts.omitTopbar) {
4561
- reportFragment.appendChild(this._renderReportTopbar(report));
4558
+ reportFragment.append(this._renderReportTopbar(report));
4562
4559
  }
4563
4560
 
4564
- reportFragment.appendChild(reportContainer);
4565
- reportContainer.appendChild(headerContainer);
4566
- reportContainer.appendChild(reportSection);
4567
- reportSection.appendChild(this._renderReportFooter(report));
4561
+ reportFragment.append(reportContainer);
4562
+ reportSection.append(this._renderReportFooter(report));
4563
+ reportContainer.append(headerContainer, reportSection);
4568
4564
 
4569
4565
  if (fullPageScreenshot) {
4570
4566
  ElementScreenshotRenderer.installFullPageScreenshot(