lighthouse 8.3.0-dev.20210907 → 8.3.0

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.
Files changed (196) hide show
  1. package/changelog.md +1 -1
  2. package/dist/report/standalone.js +196 -0
  3. package/jest.config.js +0 -4
  4. package/lighthouse-cli/cli-flags.js +6 -14
  5. package/lighthouse-cli/run.js +1 -1
  6. package/lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js +3 -9
  7. package/lighthouse-cli/test/smokehouse/report-assert.js +16 -36
  8. package/lighthouse-core/audits/large-javascript-libraries.js +166 -0
  9. package/lighthouse-core/audits/seo/http-status-code.js +6 -2
  10. package/lighthouse-core/audits/viewport.js +1 -2
  11. package/lighthouse-core/config/config-helpers.js +75 -9
  12. package/lighthouse-core/config/config.js +50 -6
  13. package/lighthouse-core/config/constants.js +0 -1
  14. package/lighthouse-core/config/default-config.js +0 -3
  15. package/lighthouse-core/config/experimental-config.js +8 -0
  16. package/lighthouse-core/config/metrics-to-audits.js +0 -1
  17. package/lighthouse-core/fraggle-rock/config/config.js +4 -3
  18. package/lighthouse-core/fraggle-rock/config/default-config.js +1 -3
  19. package/lighthouse-core/fraggle-rock/config/validation.js +0 -201
  20. package/lighthouse-core/fraggle-rock/gather/base-artifacts.js +0 -4
  21. package/lighthouse-core/fraggle-rock/gather/navigation-runner.js +8 -16
  22. package/lighthouse-core/fraggle-rock/gather/runner-helpers.js +0 -4
  23. package/lighthouse-core/fraggle-rock/gather/session.js +5 -30
  24. package/lighthouse-core/gather/driver/navigation.js +6 -7
  25. package/lighthouse-core/gather/driver/wait-for-condition.js +0 -27
  26. package/lighthouse-core/gather/fetcher.js +7 -17
  27. package/lighthouse-core/gather/gather-runner.js +0 -1
  28. package/lighthouse-core/gather/gatherers/seo/robots-txt.js +6 -2
  29. package/lighthouse-core/gather/gatherers/seo/tap-targets.js +2 -2
  30. package/lighthouse-core/gather/gatherers/stacks.js +1 -1
  31. package/lighthouse-core/lib/asset-saver.js +2 -2
  32. package/lighthouse-core/lib/cdt/SDK.js +0 -1
  33. package/lighthouse-core/lib/csp-evaluator.js +4 -17
  34. package/{report/generator → lighthouse-core/lib}/file-namer.js +0 -0
  35. package/lighthouse-core/lib/i18n/README.md +1 -1
  36. package/lighthouse-core/lib/i18n/i18n.js +7 -7
  37. package/lighthouse-core/lib/i18n/locales/ar-XB.json +18 -0
  38. package/lighthouse-core/lib/i18n/locales/ar.json +18 -0
  39. package/lighthouse-core/lib/i18n/locales/bg.json +18 -0
  40. package/lighthouse-core/lib/i18n/locales/ca.json +18 -0
  41. package/lighthouse-core/lib/i18n/locales/cs.json +18 -0
  42. package/lighthouse-core/lib/i18n/locales/da.json +18 -0
  43. package/lighthouse-core/lib/i18n/locales/de.json +18 -0
  44. package/lighthouse-core/lib/i18n/locales/el.json +18 -0
  45. package/lighthouse-core/lib/i18n/locales/en-GB.json +18 -0
  46. package/lighthouse-core/lib/i18n/locales/en-US.json +18 -18
  47. package/lighthouse-core/lib/i18n/locales/en-XA.json +18 -0
  48. package/lighthouse-core/lib/i18n/locales/en-XL.json +18 -18
  49. package/lighthouse-core/lib/i18n/locales/es-419.json +18 -0
  50. package/lighthouse-core/lib/i18n/locales/es.json +18 -0
  51. package/lighthouse-core/lib/i18n/locales/fi.json +18 -0
  52. package/lighthouse-core/lib/i18n/locales/fil.json +18 -0
  53. package/lighthouse-core/lib/i18n/locales/fr.json +18 -0
  54. package/lighthouse-core/lib/i18n/locales/he.json +18 -0
  55. package/lighthouse-core/lib/i18n/locales/hi.json +18 -0
  56. package/lighthouse-core/lib/i18n/locales/hr.json +18 -0
  57. package/lighthouse-core/lib/i18n/locales/hu.json +18 -0
  58. package/lighthouse-core/lib/i18n/locales/id.json +18 -0
  59. package/lighthouse-core/lib/i18n/locales/it.json +18 -0
  60. package/lighthouse-core/lib/i18n/locales/ja.json +18 -0
  61. package/lighthouse-core/lib/i18n/locales/ko.json +18 -0
  62. package/lighthouse-core/lib/i18n/locales/lt.json +18 -0
  63. package/lighthouse-core/lib/i18n/locales/lv.json +18 -0
  64. package/lighthouse-core/lib/i18n/locales/nl.json +18 -0
  65. package/lighthouse-core/lib/i18n/locales/no.json +18 -0
  66. package/lighthouse-core/lib/i18n/locales/pl.json +18 -0
  67. package/lighthouse-core/lib/i18n/locales/pt-PT.json +18 -0
  68. package/lighthouse-core/lib/i18n/locales/pt.json +18 -0
  69. package/lighthouse-core/lib/i18n/locales/ro.json +18 -0
  70. package/lighthouse-core/lib/i18n/locales/ru.json +18 -0
  71. package/lighthouse-core/lib/i18n/locales/sk.json +18 -0
  72. package/lighthouse-core/lib/i18n/locales/sl.json +18 -0
  73. package/lighthouse-core/lib/i18n/locales/sr-Latn.json +18 -0
  74. package/lighthouse-core/lib/i18n/locales/sr.json +18 -0
  75. package/lighthouse-core/lib/i18n/locales/sv.json +18 -0
  76. package/lighthouse-core/lib/i18n/locales/ta.json +18 -0
  77. package/lighthouse-core/lib/i18n/locales/te.json +18 -0
  78. package/lighthouse-core/lib/i18n/locales/th.json +18 -0
  79. package/lighthouse-core/lib/i18n/locales/tr.json +18 -0
  80. package/lighthouse-core/lib/i18n/locales/uk.json +18 -0
  81. package/lighthouse-core/lib/i18n/locales/vi.json +18 -0
  82. package/lighthouse-core/lib/i18n/locales/zh-HK.json +18 -0
  83. package/lighthouse-core/lib/i18n/locales/zh-TW.json +18 -0
  84. package/lighthouse-core/lib/i18n/locales/zh.json +18 -0
  85. package/lighthouse-core/lib/large-javascript-libraries/bundlephobia-database.json +62 -0
  86. package/lighthouse-core/lib/large-javascript-libraries/library-suggestions.js +20 -0
  87. package/lighthouse-core/lib/network-request.js +1 -3
  88. package/lighthouse-core/lib/traces/pwmetrics-events.js +2 -2
  89. package/lighthouse-core/lib/url-shim.js +1 -7
  90. package/lighthouse-core/runner.js +1 -4
  91. package/lighthouse-core/util-commonjs.js +2 -2
  92. package/now.json +1 -1
  93. package/package.json +13 -20
  94. package/report/README.md +2 -2
  95. package/report/assets/standalone-template.html +1 -0
  96. package/report/assets/styles.css +27 -23
  97. package/report/assets/templates.html +40 -37
  98. package/report/clients/bundle.js +0 -1
  99. package/report/{package.json → clients/package.json} +0 -0
  100. package/report/clients/psi.js +3 -13
  101. package/report/clients/standalone.js +1 -1
  102. package/report/{types/buffer.d.ts → clients/treemap.js} +13 -11
  103. package/report/renderer/category-renderer.js +2 -2
  104. package/report/renderer/components.js +48 -46
  105. package/report/renderer/crc-details-renderer.js +16 -16
  106. package/report/renderer/details-renderer.js +1 -1
  107. package/report/renderer/dom.js +0 -17
  108. package/report/renderer/element-screenshot-renderer.js +9 -9
  109. package/{flow-report/test/setup/global-setup.ts → report/renderer/file-namer.js} +2 -5
  110. package/report/renderer/logger.js +4 -4
  111. package/report/renderer/package.json +4 -0
  112. package/report/renderer/report-renderer.js +11 -4
  113. package/report/renderer/report-ui-features.js +656 -43
  114. package/report/renderer/text-encoding.js +1 -1
  115. package/report/renderer/util.js +2 -2
  116. package/report/{generator/report-assets.js → report-assets.js} +3 -9
  117. package/report/{generator/report-generator.js → report-generator.js} +9 -37
  118. package/report/test/clients/package.json +4 -0
  119. package/report/test/clients/psi-test.js +1 -3
  120. package/report/test/renderer/category-renderer-test.js +3 -8
  121. package/report/test/renderer/components-test.js +0 -35
  122. package/report/test/renderer/crc-details-renderer-test.js +4 -5
  123. package/report/test/renderer/details-renderer-test.js +1 -3
  124. package/report/test/renderer/dom-test.js +6 -8
  125. package/report/test/renderer/i18n-test.js +0 -1
  126. package/report/test/renderer/package.json +4 -0
  127. package/report/test/renderer/performance-category-renderer-test.js +27 -30
  128. package/report/test/renderer/pwa-category-renderer-test.js +1 -2
  129. package/report/test/renderer/report-renderer-test.js +0 -1
  130. package/report/test/renderer/report-ui-features-test.js +28 -20
  131. package/report/test/renderer/snippet-renderer-test.js +0 -1
  132. package/report/test/renderer/text-encoding-test.js +0 -2
  133. package/report/test/renderer/util-test.js +0 -1
  134. package/report/test/{generator/report-generator-test.js → report-generator-test.js} +7 -9
  135. package/third-party/chromium-synchronization/installability-errors-test.js +27 -28
  136. package/third-party/snyk/snapshot.json +0 -2
  137. package/tsconfig.json +5 -24
  138. package/types/artifacts.d.ts +18 -5
  139. package/types/{lhr/audit-details.d.ts → audit-details.d.ts} +3 -18
  140. package/types/audit.d.ts +58 -7
  141. package/types/{lhr/budget.d.ts → budget.d.ts} +0 -0
  142. package/types/bundle-phobia-cli/index.d.ts +40 -0
  143. package/types/config.d.ts +8 -3
  144. package/types/externs.d.ts +119 -5
  145. package/types/gatherer.d.ts +2 -3
  146. package/types/global-lh.d.ts +14 -16
  147. package/{report/types/report-result.d.ts → types/html-renderer.d.ts} +17 -8
  148. package/types/{lhr/i18n.d.ts → i18n.d.ts} +25 -2
  149. package/types/{lhr/lhr.d.ts → lhr.d.ts} +9 -41
  150. package/types/smokehouse.d.ts +3 -3
  151. package/types/{lhr/treemap.d.ts → treemap.d.ts} +3 -3
  152. package/flow-report/assets/standalone-flow-template.html +0 -38
  153. package/flow-report/assets/styles.css +0 -310
  154. package/flow-report/jest.config.js +0 -24
  155. package/flow-report/src/app.tsx +0 -40
  156. package/flow-report/src/common.tsx +0 -72
  157. package/flow-report/src/icons.tsx +0 -96
  158. package/flow-report/src/sidebar/flow.tsx +0 -72
  159. package/flow-report/src/sidebar/sidebar.tsx +0 -89
  160. package/flow-report/src/summary/summary.tsx +0 -178
  161. package/flow-report/src/util.ts +0 -160
  162. package/flow-report/src/wrappers/gauge.tsx +0 -40
  163. package/flow-report/src/wrappers/report-renderer.tsx +0 -46
  164. package/flow-report/src/wrappers/report.tsx +0 -71
  165. package/flow-report/standalone-flow.tsx +0 -23
  166. package/flow-report/test/app-test.tsx +0 -48
  167. package/flow-report/test/common-test.tsx +0 -131
  168. package/flow-report/test/setup/env-setup.ts +0 -25
  169. package/flow-report/test/sidebar/flow-test.tsx +0 -71
  170. package/flow-report/test/sidebar/sidebar-test.tsx +0 -53
  171. package/flow-report/test/summary/summary-test.tsx +0 -132
  172. package/flow-report/test/util-test.tsx +0 -109
  173. package/flow-report/tsconfig.json +0 -39
  174. package/flow-report/types/flow-report.d.ts +0 -27
  175. package/lighthouse-core/audits/lcp-lazy-loaded.js +0 -83
  176. package/report/.eslintrc.cjs +0 -33
  177. package/report/generator/README.md +0 -9
  178. package/report/generator/flow-report-assets.js +0 -20
  179. package/report/generator/package.json +0 -4
  180. package/report/generator/tsconfig.json +0 -28
  181. package/report/renderer/drop-down-menu.js +0 -215
  182. package/report/renderer/features-util.js +0 -26
  183. package/report/renderer/open-tab.js +0 -137
  184. package/report/renderer/topbar-features.js +0 -309
  185. package/report/test/generator/file-namer-test.js +0 -28
  186. package/report/test/generator/package.json +0 -4
  187. package/report/test-assets/faux-psi-template.html +0 -126
  188. package/report/test-assets/faux-psi.js +0 -92
  189. package/report/tsconfig.json +0 -39
  190. package/report/types/augment-dom.d.ts +0 -24
  191. package/report/types/html-renderer.d.ts +0 -28
  192. package/types/lhr/audit-result.d.ts +0 -59
  193. package/types/lhr/flow.d.ts +0 -16
  194. package/types/lhr/settings.d.ts +0 -105
  195. package/types/lhr/tsconfig.json +0 -24
  196. package/types/query-selector.d.ts +0 -36
@@ -5,7 +5,7 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
- /* global CompressionStream */
8
+ /* global btoa atob window CompressionStream Response */
9
9
 
10
10
  const btoa_ = typeof btoa !== 'undefined' ?
11
11
  btoa :
@@ -388,7 +388,7 @@ export class Util {
388
388
  }
389
389
 
390
390
  /**
391
- * @param {LH.Result['configSettings']} settings
391
+ * @param {LH.Config.Settings} settings
392
392
  * @return {!Array<{name: string, description: string}>}
393
393
  */
394
394
  static getEnvironmentDisplayValues(settings) {
@@ -411,7 +411,7 @@ export class Util {
411
411
  }
412
412
 
413
413
  /**
414
- * @param {LH.Result['configSettings']} settings
414
+ * @param {LH.Config.Settings} settings
415
415
  * @return {{deviceEmulation: string, networkThrottling: string, cpuThrottling: string}}
416
416
  */
417
417
  static getEmulationDescriptions(settings) {
@@ -7,12 +7,9 @@
7
7
 
8
8
  const fs = require('fs');
9
9
 
10
- const flowReportAssets = require('./flow-report-assets.js');
11
-
12
- const REPORT_TEMPLATE = fs.readFileSync(__dirname + '/../assets/standalone-template.html',
13
- 'utf8');
14
- const REPORT_JAVASCRIPT = fs.readFileSync(__dirname + '/../../dist/report/standalone.js', 'utf8');
15
- const REPORT_CSS = fs.readFileSync(__dirname + '/../assets/styles.css', 'utf8');
10
+ const REPORT_TEMPLATE = fs.readFileSync(__dirname + '/assets/standalone-template.html', 'utf8');
11
+ const REPORT_JAVASCRIPT = fs.readFileSync(__dirname + '/../dist/report/standalone.js', 'utf8');
12
+ const REPORT_CSS = fs.readFileSync(__dirname + '/assets/styles.css', 'utf8');
16
13
 
17
14
  // Changes to this export interface should be reflected in build/build-dt-report-resources.js
18
15
  // and clients/devtools-report-assets.js
@@ -20,7 +17,4 @@ module.exports = {
20
17
  REPORT_TEMPLATE,
21
18
  REPORT_JAVASCRIPT,
22
19
  REPORT_CSS,
23
- // Flow report assets are not needed for every bundle.
24
- // Ignoring flow-report-assets.js (e.g. `browserify.ignore`) will remove the flow assets from the bundle.
25
- ...flowReportAssets,
26
20
  };
@@ -7,9 +7,6 @@
7
7
 
8
8
  const htmlReportAssets = require('./report-assets.js');
9
9
 
10
- /** @typedef {import('../../types/lhr/lhr').default} LHResult */
11
- /** @typedef {import('../../types/lhr/flow').default} FlowResult */
12
-
13
10
  class ReportGenerator {
14
11
  /**
15
12
  * Replaces all the specified strings in source without serial replacements.
@@ -31,23 +28,15 @@ class ReportGenerator {
31
28
  }
32
29
 
33
30
  /**
34
- * @param {unknown} object
35
- * @return {string}
36
- */
37
- static sanitizeJson(object) {
38
- return JSON.stringify(object)
39
- .replace(/</g, '\\u003c') // replaces opening script tags
40
- .replace(/\u2028/g, '\\u2028') // replaces line separators ()
41
- .replace(/\u2029/g, '\\u2029'); // replaces paragraph separators
42
- }
43
-
44
- /**
45
- * Returns the standalone report HTML as a string with the report JSON and renderer JS inlined.
46
- * @param {LHResult} lhr
31
+ * Returns the report HTML as a string with the report JSON and renderer JS inlined.
32
+ * @param {LH.Result} lhr
47
33
  * @return {string}
48
34
  */
49
35
  static generateReportHtml(lhr) {
50
- const sanitizedJson = ReportGenerator.sanitizeJson(lhr);
36
+ const sanitizedJson = JSON.stringify(lhr)
37
+ .replace(/</g, '\\u003c') // replaces opening script tags
38
+ .replace(/\u2028/g, '\\u2028') // replaces line separators ()
39
+ .replace(/\u2029/g, '\\u2029'); // replaces paragraph separators
51
40
  // terser does its own sanitization, but keep this basic replace for when
52
41
  // we want to generate a report without minification.
53
42
  const sanitizedJavascript = htmlReportAssets.REPORT_JAVASCRIPT.replace(/<\//g, '\\u003c/');
@@ -59,23 +48,6 @@ class ReportGenerator {
59
48
  ]);
60
49
  }
61
50
 
62
- /**
63
- * Returns the standalone flow report HTML as a string with the report JSON and renderer JS inlined.
64
- * @param {FlowResult} flow
65
- * @return {string}
66
- */
67
- static generateFlowReportHtml(flow) {
68
- const sanitizedJson = ReportGenerator.sanitizeJson(flow);
69
- return ReportGenerator.replaceStrings(htmlReportAssets.FLOW_REPORT_TEMPLATE, [
70
- /* eslint-disable max-len */
71
- {search: '%%LIGHTHOUSE_FLOW_JSON%%', replacement: sanitizedJson},
72
- {search: '%%LIGHTHOUSE_FLOW_JAVASCRIPT%%', replacement: htmlReportAssets.FLOW_REPORT_JAVASCRIPT},
73
- {search: '/*%%LIGHTHOUSE_FLOW_CSS%%*/', replacement: htmlReportAssets.FLOW_REPORT_CSS},
74
- {search: '/*%%LIGHTHOUSE_CSS%%*/', replacement: htmlReportAssets.REPORT_CSS},
75
- /* eslint-enable max-len */
76
- ]);
77
- }
78
-
79
51
  /**
80
52
  * Converts the results to a CSV formatted string
81
53
  * Each row describes the result of 1 audit with
@@ -85,7 +57,7 @@ class ReportGenerator {
85
57
  * - the score type that is used for the audit
86
58
  * - the score value of the audit
87
59
  *
88
- * @param {LHResult} lhr
60
+ * @param {LH.Result} lhr
89
61
  * @return {string}
90
62
  */
91
63
  static generateReportCSV(lhr) {
@@ -122,8 +94,8 @@ class ReportGenerator {
122
94
 
123
95
  /**
124
96
  * Creates the results output in a format based on the `mode`.
125
- * @param {LHResult} lhr
126
- * @param {LHResult['configSettings']['output']} outputModes
97
+ * @param {LH.Result} lhr
98
+ * @param {LH.Config.Settings['output']} outputModes
127
99
  * @return {string|string[]}
128
100
  */
129
101
  static generateReport(lhr, outputModes) {
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "module",
3
+ "//": "Any directory that uses `import ... from` or `export ...` must be type module. Temporary file until root package.json is type: module"
4
+ }
@@ -7,9 +7,7 @@
7
7
 
8
8
  import {strict as assert} from 'assert';
9
9
  import fs from 'fs';
10
-
11
10
  import jsdom from 'jsdom';
12
-
13
11
  import testUtils from '../../../lighthouse-core/test/test-utils.js';
14
12
  import {prepareLabData} from '../../clients/psi.js';
15
13
  import {Util} from '../../renderer/util.js';
@@ -29,7 +27,7 @@ const sampleResultsStr =
29
27
 
30
28
  /* eslint-env jest */
31
29
 
32
- describe('PSI', () => {
30
+ describe('DOM', () => {
33
31
  let document;
34
32
  beforeAll(() => {
35
33
  global.Util = Util;
@@ -5,12 +5,11 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
- /* eslint-env jest */
8
+ /* eslint-env jest, browser */
9
9
 
10
10
  import {strict as assert} from 'assert';
11
11
 
12
12
  import jsdom from 'jsdom';
13
-
14
13
  import {Util} from '../../renderer/util.js';
15
14
  import {I18n} from '../../renderer/i18n.js';
16
15
  import {DOM} from '../../renderer/dom.js';
@@ -256,9 +255,7 @@ describe('CategoryRenderer', () => {
256
255
  const categoryDOM = renderer.render(a11yCategory, sampleResults.categoryGroups);
257
256
  const percentageEl = categoryDOM.querySelectorAll('.lh-gauge__percentage');
258
257
 
259
- const scoreText = percentageEl[0].textContent;
260
- assert(!scoreText.includes('.'), 'score is integer');
261
- assert(Number(scoreText) >= 0 && Number(scoreText) <= 100, 'score is 0-100');
258
+ assert.equal(percentageEl[0].textContent, '81', 'score shows a non-dash value');
262
259
  });
263
260
  });
264
261
 
@@ -273,9 +270,7 @@ describe('CategoryRenderer', () => {
273
270
  const categoryDOM = renderer.render(category, sampleResults.categoryGroups);
274
271
 
275
272
  const gauge = categoryDOM.querySelector('.lh-gauge__percentage');
276
- const scoreText = gauge.textContent.trim();
277
- assert(!scoreText.includes('.'), 'score is integer');
278
- assert(Number(scoreText) >= 0 && Number(scoreText) <= 100, 'score is 0-100');
273
+ assert.equal(gauge.textContent.trim(), '81', 'score is 0-100');
279
274
 
280
275
  const score = categoryDOM.querySelector('.lh-category-header');
281
276
  const value = categoryDOM.querySelector('.lh-gauge__percentage');
@@ -8,10 +8,8 @@
8
8
  /* eslint-env jest */
9
9
 
10
10
  import fs from 'fs';
11
-
12
11
  import jsdom from 'jsdom';
13
12
  import expect from 'expect';
14
-
15
13
  import {DOM} from '../../renderer/dom.js';
16
14
  import {LH_ROOT} from '../../../root.js';
17
15
  import {normalizeTextNodeText} from '../../../build/build-report-components.js';
@@ -85,39 +83,6 @@ async function assertDOMTreeMatches(tmplEl) {
85
83
  }
86
84
  }
87
85
 
88
- const originalCreateElement = DOM.prototype.createElement;
89
- const originalCreateElementNS = DOM.prototype.createElementNS;
90
- beforeAll(() => {
91
- /**
92
- * @param {string} classNames
93
- */
94
- function checkPrefix(classNames) {
95
- if (!classNames) return;
96
-
97
- for (const className of classNames.split(' ')) {
98
- if (!className.startsWith('lh-')) {
99
- throw new Error(`expected classname to start with lh-, got: ${className}`);
100
- }
101
- }
102
- }
103
-
104
- DOM.prototype.createElement = function(...args) {
105
- const classNames = args[1];
106
- checkPrefix(classNames);
107
- return originalCreateElement.call(this, ...args);
108
- };
109
- DOM.prototype.createElementNS = function(...args) {
110
- const classNames = args[2];
111
- checkPrefix(classNames);
112
- return originalCreateElementNS.call(this, ...args);
113
- };
114
- });
115
-
116
- afterAll(() => {
117
- DOM.prototype.createElement = originalCreateElement;
118
- DOM.prototype.createElementNS = originalCreateElementNS;
119
- });
120
-
121
86
  for (const tmpEl of tmplEls) {
122
87
  it(`${tmpEl.id} component matches HTML source`, async () => {
123
88
  await assertDOMTreeMatches(tmpEl);
@@ -10,7 +10,6 @@
10
10
  import {strict as assert} from 'assert';
11
11
 
12
12
  import jsdom from 'jsdom';
13
-
14
13
  import {Util} from '../../renderer/util.js';
15
14
  import {I18n} from '../../renderer/i18n.js';
16
15
  import {DOM} from '../../renderer/dom.js';
@@ -89,7 +88,7 @@ describe('DetailsRenderer', () => {
89
88
 
90
89
  it('renders tree structure', () => {
91
90
  const el = CriticalRequestChainRenderer.render(dom, DETAILS, detailsRenderer);
92
- const chains = el.querySelectorAll('.lh-crc-node');
91
+ const chains = el.querySelectorAll('.crc-node');
93
92
 
94
93
  // Main request
95
94
  assert.equal(chains.length, 4, 'generates correct number of chain nodes');
@@ -100,14 +99,14 @@ describe('DetailsRenderer', () => {
100
99
  assert.equal(chains[0].querySelector('.lh-text__url a').target, '_blank');
101
100
 
102
101
  // Children
103
- assert.ok(chains[1].querySelector('.lh-crc-node__tree-marker .lh-vert-right'));
104
- assert.equal(chains[1].querySelectorAll('.lh-crc-node__tree-marker .lh-right').length, 2);
102
+ assert.ok(chains[1].querySelector('.crc-node__tree-marker .vert-right'));
103
+ assert.equal(chains[1].querySelectorAll('.crc-node__tree-marker .right').length, 2);
105
104
  assert.equal(chains[1].querySelector('.lh-text__url a').textContent, '/b.js');
106
105
  assert.equal(chains[1].querySelector('.lh-text__url a').href, 'https://example.com/b.js');
107
106
  assert.equal(chains[1].querySelector('.lh-text__url a').rel, 'noopener');
108
107
  assert.equal(chains[1].querySelector('.lh-text__url a').target, '_blank');
109
108
  assert.equal(chains[1].querySelector('.lh-text__url-host').textContent, '(example.com)');
110
- const durationNodes = chains[1].querySelectorAll('.lh-crc-node__chain-duration');
109
+ const durationNodes = chains[1].querySelectorAll('.crc-node__chain-duration');
111
110
  assert.equal(durationNodes[0].textContent, ' - 5,000\xa0ms, ');
112
111
  // Note: actual transferSize is 2000 bytes but formatter formats to KiBs.
113
112
  assert.equal(durationNodes[1].textContent, '1.95\xa0KiB');
@@ -6,9 +6,7 @@
6
6
  'use strict';
7
7
 
8
8
  import {strict as assert} from 'assert';
9
-
10
9
  import jsdom from 'jsdom';
11
-
12
10
  import {DOM} from '../../renderer/dom.js';
13
11
  import {Util} from '../../renderer/util.js';
14
12
  import {I18n} from '../../renderer/i18n.js';
@@ -111,7 +109,7 @@ describe('DetailsRenderer', () => {
111
109
 
112
110
  const crcEl = renderer.render(details);
113
111
  assert.ok(crcEl.classList.contains('lh-crc-container'));
114
- assert.strictEqual(crcEl.querySelectorAll('.lh-crc-node').length, 1);
112
+ assert.strictEqual(crcEl.querySelectorAll('.crc-node').length, 1);
115
113
  });
116
114
 
117
115
  it('renders opportunity details as a table', () => {
@@ -6,10 +6,9 @@
6
6
  'use strict';
7
7
 
8
8
  import {strict as assert} from 'assert';
9
-
10
9
  import {jest} from '@jest/globals';
11
- import jsdom from 'jsdom';
12
10
 
11
+ import jsdom from 'jsdom';
13
12
  import {DOM} from '../../renderer/dom.js';
14
13
  import {Util} from '../../renderer/util.js';
15
14
  import {I18n} from '../../renderer/i18n.js';
@@ -20,16 +19,16 @@ describe('DOM', () => {
20
19
  /** @type {DOM} */
21
20
  let dom;
22
21
  let window;
23
- let nativeCreateObjectURL;
24
22
 
25
23
  beforeAll(() => {
26
24
  Util.i18n = new I18n('en', {...Util.UIStrings});
27
25
  window = new jsdom.JSDOM().window;
28
26
 
29
- // The Node version of URL.createObjectURL isn't compatible with the jsdom blob type,
30
- // so we stub it.
31
- nativeCreateObjectURL = URL.createObjectURL;
32
- URL.createObjectURL = jest.fn(_ => `https://fake-origin/blahblah-blobid`);
27
+ // Make a lame "polyfill" since JSDOM doesn't have createObjectURL: https://github.com/jsdom/jsdom/issues/1721
28
+ const lameCOURL = jest.fn(_ => `https://fake-origin/blahblah-blobid`);
29
+ if (!URL.createObjectURL) {
30
+ URL.createObjectURL = lameCOURL;
31
+ }
33
32
 
34
33
  dom = new DOM(window.document);
35
34
  dom.setLighthouseChannel('someChannel');
@@ -37,7 +36,6 @@ describe('DOM', () => {
37
36
 
38
37
  afterAll(() => {
39
38
  Util.i18n = undefined;
40
- URL.createObjectURL = nativeCreateObjectURL;
41
39
  });
42
40
 
43
41
  describe('createElement', () => {
@@ -6,7 +6,6 @@
6
6
  'use strict';
7
7
 
8
8
  import {strict as assert} from 'assert';
9
-
10
9
  import {Util} from '../../renderer/util.js';
11
10
  import {I18n} from '../../renderer/i18n.js';
12
11
  import {isNode12SmallIcu} from '../../../lighthouse-core/test/test-utils.js';
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "module",
3
+ "//": "Any directory that uses `import ... from` or `export ...` must be type module. Temporary file until root package.json is type: module"
4
+ }
@@ -5,12 +5,11 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
- /* eslint-env jest */
8
+ /* eslint-env jest, browser */
9
9
 
10
10
  import {strict as assert} from 'assert';
11
11
 
12
12
  import jsdom from 'jsdom';
13
-
14
13
  import {Util} from '../../renderer/util.js';
15
14
  import {I18n} from '../../renderer/i18n.js';
16
15
  import URL from '../../../lighthouse-core/lib/url-shim.js';
@@ -88,11 +87,9 @@ describe('PerfCategoryRenderer', () => {
88
87
  const categoryDOM = renderer.render(category, sampleResults.categoryGroups);
89
88
 
90
89
  const oppAudits = category.auditRefs.filter(audit => audit.group === 'load-opportunities' &&
91
- !Util.showAsPassed(audit.result));
92
- const oppElements = [...categoryDOM.querySelectorAll('.lh-audit--load-opportunity')];
93
- expect(oppElements.map(e => e.id).sort()).toEqual(oppAudits.map(a => a.id).sort());
94
- expect(oppElements.length).toBeGreaterThan(0);
95
- expect(oppElements.length).toMatchInlineSnapshot('7');
90
+ audit.result.score !== 1 && audit.result.scoreDisplayMode !== 'notApplicable');
91
+ const oppElements = categoryDOM.querySelectorAll('.lh-audit--load-opportunity');
92
+ assert.equal(oppElements.length, oppAudits.length);
96
93
 
97
94
  const oppElement = oppElements[0];
98
95
  const oppSparklineBarElement = oppElement.querySelector('.lh-sparkline__bar');
@@ -117,7 +114,7 @@ describe('PerfCategoryRenderer', () => {
117
114
 
118
115
  const fakeCategory = Object.assign({}, category, {auditRefs: [auditWithError]});
119
116
  const categoryDOM = renderer.render(fakeCategory, sampleResults.categoryGroups);
120
- const tooltipEl = categoryDOM.querySelector('.lh-audit--load-opportunity .lh-tooltip--error');
117
+ const tooltipEl = categoryDOM.querySelector('.lh-audit--load-opportunity .tooltip--error');
121
118
  assert.ok(tooltipEl, 'did not render error message');
122
119
  assert.ok(/Yikes!!/.test(tooltipEl.textContent));
123
120
  });
@@ -242,16 +239,16 @@ describe('PerfCategoryRenderer', () => {
242
239
  const href = renderer._getScoringCalculatorHref(categoryClone.auditRefs);
243
240
  const url = new URL(href);
244
241
  expect(url.hash.split('&')).toMatchInlineSnapshot(`
245
- Array [
246
- "#FCP=6844",
247
- "SI=8114",
248
- "LCP=6844",
249
- "TTI=8191",
250
- "TBT=1221",
251
- "CLS=0",
252
- "FMP=6844",
253
- ]
254
- `);
242
+ Array [
243
+ "#FCP=3969",
244
+ "SI=4417",
245
+ "LCP=4927",
246
+ "TTI=4927",
247
+ "TBT=117",
248
+ "CLS=0",
249
+ "FMP=3969",
250
+ ]
251
+ `);
255
252
  });
256
253
 
257
254
  it('also appends device and version number', () => {
@@ -263,18 +260,18 @@ Array [
263
260
  const url = new URL(href);
264
261
  try {
265
262
  expect(url.hash.split('&')).toMatchInlineSnapshot(`
266
- Array [
267
- "#FCP=6844",
268
- "SI=8114",
269
- "LCP=6844",
270
- "TTI=8191",
271
- "TBT=1221",
272
- "CLS=0.14",
273
- "FMP=6844",
274
- "device=mobile",
275
- "version=6.0.0",
276
- ]
277
- `);
263
+ Array [
264
+ "#FCP=3969",
265
+ "SI=4417",
266
+ "LCP=4927",
267
+ "TTI=4927",
268
+ "TBT=117",
269
+ "CLS=0.42",
270
+ "FMP=3969",
271
+ "device=mobile",
272
+ "version=6.0.0",
273
+ ]
274
+ `);
278
275
  } finally {
279
276
  Util.reportJson = null;
280
277
  }
@@ -5,12 +5,11 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
- /* eslint-env jest */
8
+ /* eslint-env jest, browser */
9
9
 
10
10
  import {strict as assert} from 'assert';
11
11
 
12
12
  import jsdom from 'jsdom';
13
-
14
13
  import {Util} from '../../renderer/util.js';
15
14
  import {I18n} from '../../renderer/i18n.js';
16
15
  import {DOM} from '../../renderer/dom.js';
@@ -10,7 +10,6 @@
10
10
  import {strict as assert} from 'assert';
11
11
 
12
12
  import jsdom from 'jsdom';
13
-
14
13
  import {Util} from '../../renderer/util.js';
15
14
  import URL from '../../../lighthouse-core/lib/url-shim.js';
16
15
  import {DOM} from '../../renderer/dom.js';
@@ -8,10 +8,8 @@
8
8
  /* eslint-env jest */
9
9
 
10
10
  import {strict as assert} from 'assert';
11
-
12
11
  import jsdom from 'jsdom';
13
-
14
- import reportAssets from '../../generator/report-assets.js';
12
+ import reportAssets from '../../report-assets.js';
15
13
  import {Util} from '../../renderer/util.js';
16
14
  import {DOM} from '../../renderer/dom.js';
17
15
  import {DetailsRenderer} from '../../renderer/details-renderer.js';
@@ -159,6 +157,16 @@ describe('ReportUIFeatures', () => {
159
157
  },
160
158
  },
161
159
  ];
160
+ // Sample json currently doesn't have any results for `unused-javascript`, so
161
+ // headings is empty. Can delete this block of code if that changes.
162
+ expect(lhr.audits['unused-javascript'].details.headings).toHaveLength(0);
163
+ lhr.audits['unused-javascript'].details.headings = [
164
+ /* t-disable max-len */
165
+ {key: 'url', valueType: 'url', subItemsHeading: {key: 'source', valueType: 'code'}},
166
+ {key: 'totalBytes', valueType: 'bytes', subItemsHeading: {key: 'sourceBytes'}},
167
+ {key: 'wastedBytes', valueType: 'bytes', subItemsHeading: {key: 'sourceWastedBytes'}},
168
+ /* eslint-enable max-len */
169
+ ];
162
170
 
163
171
  // Only third party URLs to test that checkbox is hidden
164
172
  lhr.audits['render-blocking-resources'].details.items = [
@@ -276,7 +284,7 @@ describe('ReportUIFeatures', () => {
276
284
  const lhr = JSON.parse(JSON.stringify(sampleResults));
277
285
  lhr.categories.performance.score = 0.5;
278
286
  const container = render(lhr);
279
- assert.ok(container.querySelector('.lh-score100') === null, 'has no fireworks treatment');
287
+ assert.ok(container.querySelector('.score100') === null, 'has no fireworks treatment');
280
288
  });
281
289
 
282
290
  it('should render an all 100 report with fireworks', () => {
@@ -285,7 +293,7 @@ describe('ReportUIFeatures', () => {
285
293
  element.score = 1;
286
294
  });
287
295
  const container = render(lhr);
288
- assert.ok(container.querySelector('.lh-score100'), 'has fireworks treatment');
296
+ assert.ok(container.querySelector('.score100'), 'has fireworks treatment');
289
297
  });
290
298
 
291
299
  it('should show fireworks for all 100s except PWA', () => {
@@ -296,7 +304,7 @@ describe('ReportUIFeatures', () => {
296
304
  lhr.categories.pwa.score = 0;
297
305
 
298
306
  const container = render(lhr);
299
- assert.ok(container.querySelector('.lh-score100'), 'has fireworks treatment');
307
+ assert.ok(container.querySelector('.score100'), 'has fireworks treatment');
300
308
  });
301
309
 
302
310
  it('should not render fireworks if all core categories are not present', () => {
@@ -307,7 +315,7 @@ describe('ReportUIFeatures', () => {
307
315
  element.score = 1;
308
316
  });
309
317
  const container = render(lhr);
310
- assert.ok(container.querySelector('.lh-score100') === null, 'has no fireworks treatment');
318
+ assert.ok(container.querySelector('.score100') === null, 'has no fireworks treatment');
311
319
  });
312
320
  });
313
321
 
@@ -334,32 +342,32 @@ describe('ReportUIFeatures', () => {
334
342
  window = dom.document().defaultView;
335
343
  const features = new ReportUIFeatures(dom);
336
344
  features.initFeatures(sampleResults);
337
- dropDown = features._topbar._dropDownMenu;
345
+ dropDown = features._dropDown;
338
346
  });
339
347
 
340
348
  it('click should toggle active class', () => {
341
349
  dropDown._toggleEl.click();
342
- assert.ok(dropDown._toggleEl.classList.contains('lh-active'));
350
+ assert.ok(dropDown._toggleEl.classList.contains('active'));
343
351
 
344
352
  dropDown._toggleEl.click();
345
- assert.ok(!dropDown._toggleEl.classList.contains('lh-active'));
353
+ assert.ok(!dropDown._toggleEl.classList.contains('active'));
346
354
  });
347
355
 
348
356
 
349
357
  it('Escape key removes active class', () => {
350
358
  dropDown._toggleEl.click();
351
- assert.ok(dropDown._toggleEl.classList.contains('lh-active'));
359
+ assert.ok(dropDown._toggleEl.classList.contains('active'));
352
360
 
353
361
  const escape = new window.KeyboardEvent('keydown', {keyCode: /* ESC */ 27});
354
362
  dom.document().dispatchEvent(escape);
355
- assert.ok(!dropDown._toggleEl.classList.contains('lh-active'));
363
+ assert.ok(!dropDown._toggleEl.classList.contains('active'));
356
364
  });
357
365
 
358
366
  ['ArrowUp', 'ArrowDown', 'Enter', ' '].forEach((code) => {
359
367
  it(`'${code}' adds active class`, () => {
360
368
  const event = new window.KeyboardEvent('keydown', {code});
361
369
  dropDown._toggleEl.dispatchEvent(event);
362
- assert.ok(dropDown._toggleEl.classList.contains('lh-active'));
370
+ assert.ok(dropDown._toggleEl.classList.contains('active'));
363
371
  });
364
372
  });
365
373
 
@@ -471,14 +479,14 @@ describe('ReportUIFeatures', () => {
471
479
  describe('onMenuFocusOut', () => {
472
480
  beforeEach(() => {
473
481
  dropDown._toggleEl.click();
474
- assert.ok(dropDown._toggleEl.classList.contains('lh-active'));
482
+ assert.ok(dropDown._toggleEl.classList.contains('active'));
475
483
  });
476
484
 
477
485
  it('should toggle active class when focus relatedTarget is null', () => {
478
486
  const event = new window.FocusEvent('focusout', {relatedTarget: null});
479
487
  dropDown.onMenuFocusOut(event);
480
488
 
481
- assert.ok(!dropDown._toggleEl.classList.contains('lh-active'));
489
+ assert.ok(!dropDown._toggleEl.classList.contains('active'));
482
490
  });
483
491
 
484
492
  it('should toggle active class when focus relatedTarget is document.body', () => {
@@ -486,7 +494,7 @@ describe('ReportUIFeatures', () => {
486
494
  const event = new window.FocusEvent('focusout', {relatedTarget});
487
495
  dropDown.onMenuFocusOut(event);
488
496
 
489
- assert.ok(!dropDown._toggleEl.classList.contains('lh-active'));
497
+ assert.ok(!dropDown._toggleEl.classList.contains('active'));
490
498
  });
491
499
 
492
500
  it('should toggle active class when focus relatedTarget is _toggleEl', () => {
@@ -494,7 +502,7 @@ describe('ReportUIFeatures', () => {
494
502
  const event = new window.FocusEvent('focusout', {relatedTarget});
495
503
  dropDown.onMenuFocusOut(event);
496
504
 
497
- assert.ok(!dropDown._toggleEl.classList.contains('lh-active'));
505
+ assert.ok(!dropDown._toggleEl.classList.contains('active'));
498
506
  });
499
507
 
500
508
  it('should not toggle active class when focus relatedTarget is a menu item', () => {
@@ -502,7 +510,7 @@ describe('ReportUIFeatures', () => {
502
510
  const event = new window.FocusEvent('focusout', {relatedTarget});
503
511
  dropDown.onMenuFocusOut(event);
504
512
 
505
- assert.ok(dropDown._toggleEl.classList.contains('lh-active'));
513
+ assert.ok(dropDown._toggleEl.classList.contains('active'));
506
514
  });
507
515
  });
508
516
  });
@@ -512,10 +520,10 @@ describe('ReportUIFeatures', () => {
512
520
  const lhr = JSON.parse(JSON.stringify(sampleResults));
513
521
 
514
522
  expect(lhr.audits['script-treemap-data']).not.toBeUndefined();
515
- expect(render(lhr).querySelector('.lh-button.lh-report-icon--treemap')).toBeTruthy();
523
+ expect(render(lhr).querySelector('.lh-button.report-icon--treemap')).toBeTruthy();
516
524
 
517
525
  delete lhr.audits['script-treemap-data'];
518
- expect(render(lhr).querySelector('.lh-button.lh-report-icon--treemap')).toBeNull();
526
+ expect(render(lhr).querySelector('.lh-button.report-icon--treemap')).toBeNull();
519
527
  });
520
528
  });
521
529
 
@@ -10,7 +10,6 @@
10
10
  import {strict as assert} from 'assert';
11
11
 
12
12
  import jsdom from 'jsdom';
13
-
14
13
  import {Util} from '../../renderer/util.js';
15
14
  import {I18n} from '../../renderer/i18n.js';
16
15
  import {DOM} from '../../renderer/dom.js';
@@ -6,9 +6,7 @@
6
6
  'use strict';
7
7
 
8
8
  import fs from 'fs';
9
-
10
9
  import pako from 'pako';
11
-
12
10
  import {TextEncoding} from '../../renderer/text-encoding.js';
13
11
  import {LH_ROOT} from '../../../root.js';
14
12