lighthouse 9.5.0-dev.20220628 → 9.5.0-dev.20220629

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 (51) hide show
  1. package/dist/report/bundle.esm.js +7 -6
  2. package/dist/report/flow.js +24 -24
  3. package/dist/report/standalone.js +19 -19
  4. package/flow-report/test/common-test.tsx +5 -4
  5. package/flow-report/test/flow-report-pptr-test.ts +4 -7
  6. package/flow-report/test/run-flow-report-tests.sh +20 -0
  7. package/flow-report/test/setup/env-setup.ts +44 -24
  8. package/flow-report/test/sidebar/sidebar-test.tsx +0 -1
  9. package/flow-report/test/topbar-test.tsx +5 -5
  10. package/flow-report/test/util-test.tsx +3 -3
  11. package/flow-report/tsconfig.json +4 -1
  12. package/lighthouse-cli/cli-flags.js +313 -305
  13. package/lighthouse-cli/test/smokehouse/report-assert-test.js +1 -1
  14. package/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +30 -5
  15. package/lighthouse-core/config/config-plugin.js +26 -0
  16. package/lighthouse-core/fraggle-rock/gather/navigation-runner.js +1 -0
  17. package/lighthouse-core/gather/gather-runner.js +1 -0
  18. package/lighthouse-core/gather/gatherers/main-document-content.js +0 -2
  19. package/lighthouse-core/lib/lh-env.js +1 -1
  20. package/lighthouse-core/lib/navigation-error.js +26 -7
  21. package/lighthouse-core/util-commonjs.js +7 -6
  22. package/package.json +24 -19
  23. package/report/renderer/util.js +7 -6
  24. package/report/test/.eslintrc.cjs +4 -1
  25. package/report/test/clients/bundle-test.js +4 -4
  26. package/report/test/generator/report-generator-test.js +3 -1
  27. package/report/test/renderer/category-renderer-test.js +3 -3
  28. package/report/test/renderer/components-test.js +36 -34
  29. package/report/test/renderer/crc-details-renderer-test.js +2 -2
  30. package/report/test/renderer/details-renderer-test.js +2 -2
  31. package/report/test/renderer/dom-test.js +4 -4
  32. package/report/test/renderer/element-screenshot-renderer-test.js +3 -2
  33. package/report/test/renderer/performance-category-renderer-test.js +4 -4
  34. package/report/test/renderer/pwa-category-renderer-test.js +3 -3
  35. package/report/test/renderer/report-renderer-axe-test.js +6 -8
  36. package/report/test/renderer/report-renderer-test.js +5 -5
  37. package/report/test/renderer/report-ui-features-test.js +8 -8
  38. package/report/test/renderer/snippet-renderer-test.js +2 -2
  39. package/report/test/renderer/text-encoding-test.js +2 -2
  40. package/report/test/renderer/util-test.js +1 -1
  41. package/root.js +0 -18
  42. package/shared/localization/locales/en-US.json +3 -0
  43. package/shared/localization/locales/en-XL.json +3 -0
  44. package/shared/test/localization/.eslintrc.cjs +4 -1
  45. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +1 -1
  46. package/third-party/chromium-synchronization/installability-errors-test.js +1 -3
  47. package/types/test.d.ts +53 -0
  48. package/flow-report/jest.config.js +0 -24
  49. package/flow-report/test/setup/global-setup.ts +0 -11
  50. package/jest.config.js +0 -30
  51. package/types/jest.d.ts +0 -25
@@ -6,8 +6,8 @@
6
6
 
7
7
  /* eslint-disable no-control-regex */
8
8
 
9
+ import {readJson} from '../../../lighthouse-core/test/test-utils.js';
9
10
  import {findDifferences, getAssertionReport} from './report-assert.js';
10
- import {readJson} from '../../../root.js';
11
11
 
12
12
  describe('findDiffersences', () => {
13
13
  const testCases = {
@@ -33,6 +33,9 @@ const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings);
33
33
 
34
34
  const IGNORE_THRESHOLD_IN_BYTES = 4096;
35
35
 
36
+ // Ignore up to 12KB of waste if an effort was made with breakpoints.
37
+ const IGNORE_THRESHOLD_IN_BYTES_BREAKPOINTS_PRESENT = 12288;
38
+
36
39
  class UsesResponsiveImages extends ByteEfficiencyAudit {
37
40
  /**
38
41
  * @return {LH.Audit.Meta}
@@ -112,6 +115,18 @@ class UsesResponsiveImages extends ByteEfficiencyAudit {
112
115
  };
113
116
  }
114
117
 
118
+
119
+ /**
120
+ * @param {LH.Artifacts.ImageElement} image
121
+ * @return {number};
122
+ */
123
+ static determineAllowableWaste(image) {
124
+ if (image.srcset || image.isPicture) {
125
+ return IGNORE_THRESHOLD_IN_BYTES_BREAKPOINTS_PRESENT;
126
+ }
127
+ return IGNORE_THRESHOLD_IN_BYTES;
128
+ }
129
+
115
130
  /**
116
131
  * @param {LH.Artifacts} artifacts
117
132
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
@@ -126,6 +141,8 @@ class UsesResponsiveImages extends ByteEfficiencyAudit {
126
141
  const ViewportDimensions = artifacts.ViewportDimensions;
127
142
  /** @type {Map<string, LH.Audit.ByteEfficiencyItem>} */
128
143
  const resultsMap = new Map();
144
+ /** @type {Array<string>} */
145
+ const passedImageList = [];
129
146
  for (const image of images) {
130
147
  // Give SVG a free pass because creating a "responsive" SVG is of questionable value.
131
148
  // Ignore CSS images because it's difficult to determine what is a spritesheet,
@@ -147,15 +164,23 @@ class UsesResponsiveImages extends ByteEfficiencyAudit {
147
164
  );
148
165
  if (!processed) continue;
149
166
 
150
- // Don't warn about an image that was later used appropriately
167
+ // Verify the image wastes more than the minimum.
168
+ const exceedsAllowableWaste = processed.wastedBytes > this.determineAllowableWaste(image);
169
+
151
170
  const existing = resultsMap.get(processed.url);
152
- if (!existing || existing.wastedBytes > processed.wastedBytes) {
153
- resultsMap.set(processed.url, processed);
171
+ // Don't warn about an image that was later used appropriately, or wastes a trivial amount of data.
172
+ if (exceedsAllowableWaste && !passedImageList.includes(processed.url)) {
173
+ if ((!existing || existing.wastedBytes > processed.wastedBytes)) {
174
+ resultsMap.set(processed.url, processed);
175
+ }
176
+ } else {
177
+ // Ensure this url passes for future tests.
178
+ resultsMap.delete(processed.url);
179
+ passedImageList.push(processed.url);
154
180
  }
155
181
  }
156
182
 
157
- const items = Array.from(resultsMap.values())
158
- .filter(item => item.wastedBytes > IGNORE_THRESHOLD_IN_BYTES);
183
+ const items = Array.from(resultsMap.values());
159
184
 
160
185
  /** @type {LH.Audit.Details.Opportunity['headings']} */
161
186
  const headings = [
@@ -23,6 +23,24 @@ function isObjectOfUnknownProperties(val) {
23
23
  return typeof val === 'object' && val !== null && !Array.isArray(val);
24
24
  }
25
25
 
26
+ /**
27
+ * @param {unknown} str
28
+ * @return {str is LH.Gatherer.GatherMode}
29
+ */
30
+ function objectIsGatherMode(str) {
31
+ if (typeof str !== 'string') return false;
32
+ return str === 'navigation' || str === 'timespan' || str === 'snapshot';
33
+ }
34
+
35
+ /**
36
+ * @param {unknown} arr
37
+ * @return {arr is Array<LH.Gatherer.GatherMode>}
38
+ */
39
+ function isArrayOfGatherModes(arr) {
40
+ if (!Array.isArray(arr)) return false;
41
+ return arr.every(objectIsGatherMode);
42
+ }
43
+
26
44
  /**
27
45
  * Asserts that obj has no own properties, throwing a nice error message if it does.
28
46
  * Plugin and object name are included for nicer logging.
@@ -124,6 +142,7 @@ class ConfigPlugin {
124
142
  description,
125
143
  manualDescription,
126
144
  auditRefs: auditRefsJson,
145
+ supportedModes,
127
146
  ...invalidRest
128
147
  } = categoryJson;
129
148
 
@@ -138,6 +157,12 @@ class ConfigPlugin {
138
157
  if (!i18n.isStringOrIcuMessage(manualDescription) && manualDescription !== undefined) {
139
158
  throw new Error(`${pluginName} has an invalid category manualDescription.`);
140
159
  }
160
+ if (!isArrayOfGatherModes(supportedModes) && supportedModes !== undefined) {
161
+ throw new Error(
162
+ `${pluginName} supportedModes must be an array, ` +
163
+ `valid array values are "navigation", "timespan", and "snapshot".`
164
+ );
165
+ }
141
166
  const auditRefs = ConfigPlugin._parseAuditRefsList(auditRefsJson, pluginName);
142
167
 
143
168
  return {
@@ -145,6 +170,7 @@ class ConfigPlugin {
145
170
  auditRefs,
146
171
  description: description,
147
172
  manualDescription: manualDescription,
173
+ supportedModes,
148
174
  };
149
175
  }
150
176
 
@@ -178,6 +178,7 @@ async function _computeNavigationResult(
178
178
  url: mainDocumentUrl,
179
179
  loadFailureMode: navigationContext.navigation.loadFailureMode,
180
180
  networkRecords: debugData.records,
181
+ warnings,
181
182
  })
182
183
  : navigationError;
183
184
 
@@ -604,6 +604,7 @@ class GatherRunner {
604
604
  url: passContext.url,
605
605
  loadFailureMode: passConfig.loadFailureMode,
606
606
  networkRecords: loadData.networkRecords,
607
+ warnings: passContext.LighthouseRunWarnings,
607
608
  });
608
609
  if (pageLoadError) {
609
610
  const localizedMessage = format.getFormatted(pageLoadError.friendlyMessage,
@@ -21,7 +21,6 @@ class MainDocumentContent extends FRGatherer {
21
21
  };
22
22
 
23
23
  /**
24
- *
25
24
  * @param {LH.Gatherer.FRTransitionalContext} context
26
25
  * @param {LH.Artifacts['DevtoolsLog']} devtoolsLog
27
26
  * @return {Promise<LH.Artifacts['MainDocumentContent']>}
@@ -34,7 +33,6 @@ class MainDocumentContent extends FRGatherer {
34
33
  }
35
34
 
36
35
  /**
37
- *
38
36
  * @param {LH.Gatherer.FRTransitionalContext<'DevtoolsLog'>} context
39
37
  * @return {Promise<LH.Artifacts['MainDocumentContent']>}
40
38
  */
@@ -8,7 +8,7 @@
8
8
  const process = require('process');
9
9
 
10
10
  module.exports = {
11
- // NODE_ENV is set to test by jest and by smokehouse CLI runner
11
+ // NODE_ENV is set to test by mocha-setup.js and the smokehouse CLI runner
12
12
  // CI as a catchall for everything we do in GitHub Actions
13
13
  isUnderTest: !!process.env.CI || process.env.NODE_ENV === 'test',
14
14
  };
@@ -8,6 +8,22 @@
8
8
  const LHError = require('./lh-error.js');
9
9
  const NetworkAnalyzer = require('./dependency-graph/simulator/network-analyzer.js');
10
10
  const NetworkRequest = require('./network-request.js');
11
+ const i18n = require('./i18n/i18n.js');
12
+
13
+ const UIStrings = {
14
+ /**
15
+ * Warning shown in report when the page under test is an XHTML document, which Lighthouse does not directly support
16
+ * so we display a warning.
17
+ */
18
+ warningXhtml:
19
+ 'The page MIME type is XHTML: Lighthouse does not explicitly support this document type',
20
+ };
21
+
22
+ const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings);
23
+
24
+ // MIME types are case-insensitive but Chrome normalizes MIME types to be lowercase.
25
+ const HTML_MIME_TYPE = 'text/html';
26
+ const XHTML_MIME_TYPE = 'application/xhtml+xml';
11
27
 
12
28
  /**
13
29
  * Returns an error if the original network request failed or wasn't found.
@@ -76,16 +92,15 @@ function getInterstitialError(mainRecord, networkRecords) {
76
92
  * @return {LH.LighthouseError|undefined}
77
93
  */
78
94
  function getNonHtmlError(finalRecord) {
79
- // MIME types are case-insenstive but Chrome normalizes MIME types to be lowercase.
80
- const HTML_MIME_TYPE = 'text/html';
81
-
82
95
  // If we never requested a document, there's no doctype error, let other cases handle it.
83
96
  if (!finalRecord) return undefined;
84
97
 
85
98
  // mimeType is determined by the browser, we assume Chrome is determining mimeType correctly,
86
99
  // independently of 'Content-Type' response headers, and always sending mimeType if well-formed.
87
- if (HTML_MIME_TYPE !== finalRecord.mimeType) {
88
- return new LHError(LHError.errors.NOT_HTML, {mimeType: finalRecord.mimeType});
100
+ if (finalRecord.mimeType !== HTML_MIME_TYPE && finalRecord.mimeType !== XHTML_MIME_TYPE) {
101
+ return new LHError(LHError.errors.NOT_HTML, {
102
+ mimeType: finalRecord.mimeType,
103
+ });
89
104
  }
90
105
 
91
106
  return undefined;
@@ -95,7 +110,7 @@ function getNonHtmlError(finalRecord) {
95
110
  * Returns an error if the page load should be considered failed, e.g. from a
96
111
  * main document request failure, a security issue, etc.
97
112
  * @param {LH.LighthouseError|undefined} navigationError
98
- * @param {{url: string, loadFailureMode: LH.Gatherer.PassContext['passConfig']['loadFailureMode'], networkRecords: Array<LH.Artifacts.NetworkRequest>}} context
113
+ * @param {{url: string, loadFailureMode: LH.Gatherer.PassContext['passConfig']['loadFailureMode'], networkRecords: Array<LH.Artifacts.NetworkRequest>, warnings: Array<string | LH.IcuMessage>}} context
99
114
  * @return {LH.LighthouseError|undefined}
100
115
  */
101
116
  function getPageLoadError(navigationError, context) {
@@ -120,6 +135,10 @@ function getPageLoadError(navigationError, context) {
120
135
  finalRecord = NetworkAnalyzer.resolveRedirects(mainRecord);
121
136
  }
122
137
 
138
+ if (finalRecord?.mimeType === XHTML_MIME_TYPE) {
139
+ context.warnings.push(str_(UIStrings.warningXhtml));
140
+ }
141
+
123
142
  const networkError = getNetworkError(mainRecord);
124
143
  const interstitialError = getInterstitialError(mainRecord, networkRecords);
125
144
  const nonHtmlError = getNonHtmlError(finalRecord);
@@ -145,10 +164,10 @@ function getPageLoadError(navigationError, context) {
145
164
  return navigationError;
146
165
  }
147
166
 
148
-
149
167
  module.exports = {
150
168
  getNetworkError,
151
169
  getInterstitialError,
152
170
  getPageLoadError,
153
171
  getNonHtmlError,
172
+ UIStrings,
154
173
  };
@@ -572,15 +572,16 @@ class Util {
572
572
  */
573
573
  Util.reportJson = null;
574
574
 
575
+ let svgSuffix = 0;
575
576
  /**
576
577
  * An always-increasing counter for making unique SVG ID suffixes.
577
578
  */
578
- Util.getUniqueSuffix = (() => {
579
- let svgSuffix = 0;
580
- return function() {
581
- return svgSuffix++;
582
- };
583
- })();
579
+ Util.getUniqueSuffix = () => {
580
+ return svgSuffix++;
581
+ };
582
+ Util.resetUniqueSuffix = () => {
583
+ svgSuffix = 0;
584
+ };
584
585
 
585
586
  /**
586
587
  * Report-renderer-specific strings.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lighthouse",
3
- "version": "9.5.0-dev.20220628",
3
+ "version": "9.5.0-dev.20220629",
4
4
  "description": "Automated auditing, performance metrics, and best practices for the web.",
5
5
  "main": "./lighthouse-core/index.js",
6
6
  "bin": {
@@ -35,24 +35,24 @@
35
35
  "smoke": "node lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js",
36
36
  "debug": "node --inspect-brk ./lighthouse-cli/index.js",
37
37
  "start": "yarn build-report --standalone && node ./lighthouse-cli/index.js",
38
- "jest": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js",
38
+ "mocha": "node lighthouse-core/test/scripts/run-mocha-tests.js",
39
39
  "test": "yarn diff:sample-json && yarn lint --quiet && yarn unit && yarn type-check",
40
40
  "test-bundle": "yarn smoke --runner bundle --retries=2",
41
- "test-clients": "yarn jest \"$PWD/clients/\" && yarn jest --testMatch=\"**/clients/test/**/*-test-pptr.js\"",
42
- "test-viewer": "yarn unit-viewer && yarn jest --testMatch=\"**/viewer/**/*-test-pptr.js\"",
43
- "test-treemap": "yarn unit-treemap && yarn jest --testMatch=\"**/treemap/**/*-test-pptr.js\"",
41
+ "test-clients": "yarn mocha --testMatch clients/**/*-test.js && yarn mocha --testMatch clients/**/*-test-pptr.js",
42
+ "test-viewer": "yarn unit-viewer && yarn mocha --testMatch viewer/**/*-test-pptr.js --timeout 35000",
43
+ "test-treemap": "yarn unit-treemap && yarn mocha --testMatch treemap/**/*-test-pptr.js --timeout 35000",
44
44
  "test-lantern": "bash lighthouse-core/scripts/test-lantern.sh",
45
45
  "test-legacy-javascript": "bash lighthouse-core/scripts/test-legacy-javascript.sh",
46
46
  "test-docs": "yarn --cwd docs/recipes/ test",
47
47
  "test-proto": "yarn compile-proto && yarn build-proto-roundtrip",
48
- "unit-core": "yarn jest \"lighthouse-core\"",
49
- "unit-cli": "yarn jest \"lighthouse-cli/\"",
50
- "unit-report": "yarn jest \"report/\"",
51
- "unit-treemap": "yarn jest \"treemap/.*-test.js\"",
52
- "unit-viewer": "yarn jest \"viewer/.*-test.js\"",
53
- "unit-flow": "yarn jest \"flow-report/.*-test.[tj]s[x]?\"",
54
- "unit": "yarn jest",
55
- "unit:ci": "NODE_OPTIONS=--max-old-space-size=8192 npm run jest --ci .",
48
+ "unit-core": "yarn mocha lighthouse-core",
49
+ "unit-cli": "yarn mocha --testMatch lighthouse-cli/**/*-test.js",
50
+ "unit-report": "yarn mocha --testMatch report/**/*-test.js",
51
+ "unit-treemap": "yarn mocha --testMatch treemap/**/*-test.js",
52
+ "unit-viewer": "yarn mocha --testMatch viewer/**/*-test.js",
53
+ "unit-flow": "bash flow-report/test/run-flow-report-tests.sh",
54
+ "unit": "yarn unit-flow && yarn mocha",
55
+ "unit:ci": "NODE_OPTIONS=--max-old-space-size=8192 npm run unit --forbid-only",
56
56
  "core-unit": "yarn unit-core",
57
57
  "cli-unit": "yarn unit-cli",
58
58
  "viewer-unit": "yarn unit-viewer",
@@ -96,6 +96,8 @@
96
96
  },
97
97
  "devDependencies": {
98
98
  "@build-tracker/cli": "^1.0.0-beta.15",
99
+ "@esbuild-kit/esm-loader": "^2.1.1",
100
+ "@jest/fake-timers": "^28.1.0",
99
101
  "@rollup/plugin-alias": "^3.1.2",
100
102
  "@rollup/plugin-commonjs": "^20.0.0",
101
103
  "@rollup/plugin-dynamic-import-vars": "^1.1.1",
@@ -103,7 +105,7 @@
103
105
  "@rollup/plugin-node-resolve": "^13.0.4",
104
106
  "@rollup/plugin-typescript": "^8.2.5",
105
107
  "@stadtlandnetz/rollup-plugin-postprocess": "^1.1.0",
106
- "@testing-library/preact": "^2.0.1",
108
+ "@testing-library/preact": "^3.1.1",
107
109
  "@testing-library/preact-hooks": "^1.1.0",
108
110
  "@types/archiver": "^2.1.2",
109
111
  "@types/chrome": "^0.0.154",
@@ -113,10 +115,10 @@
113
115
  "@types/estree": "^0.0.50",
114
116
  "@types/gh-pages": "^2.0.0",
115
117
  "@types/google.analytics": "0.0.39",
116
- "@types/jest": "^27.0.3",
117
118
  "@types/jpeg-js": "^0.3.7",
118
119
  "@types/jsdom": "^16.2.13",
119
120
  "@types/lodash": "^4.14.178",
121
+ "@types/mocha": "^9.0.0",
120
122
  "@types/node": "*",
121
123
  "@types/pako": "^1.0.1",
122
124
  "@types/resize-observer-browser": "^0.1.1",
@@ -130,7 +132,7 @@
130
132
  "acorn": "^8.5.0",
131
133
  "angular": "^1.7.4",
132
134
  "archiver": "^3.0.0",
133
- "c8": "^7.4.0",
135
+ "c8": "^7.11.3",
134
136
  "chalk": "^2.4.1",
135
137
  "chrome-devtools-frontend": "1.0.1012379",
136
138
  "concurrently": "^6.4.0",
@@ -146,22 +148,25 @@
146
148
  "eslint-plugin-import": "^2.25.3",
147
149
  "eslint-plugin-local-rules": "1.1.0",
148
150
  "event-target-shim": "^6.0.2",
151
+ "expect": "^28.1.0",
149
152
  "firebase": "^9.0.2",
150
153
  "gh-pages": "^2.0.1",
151
154
  "glob": "^7.1.3",
152
155
  "idb-keyval": "2.2.0",
153
156
  "intl-messageformat-parser": "^1.8.1",
154
- "jest": "27.1.1",
157
+ "jest-mock": "^27.3.0",
158
+ "jest-snapshot": "^28.1.0",
155
159
  "jsdom": "^12.2.0",
156
160
  "jsonld": "^5.2.0",
157
161
  "jsonlint-mod": "^1.7.6",
158
162
  "lighthouse-plugin-publisher-ads": "^1.5.4",
159
163
  "magic-string": "^0.25.7",
160
164
  "mime-types": "^2.1.30",
165
+ "mocha": "^10.0.0",
161
166
  "node-fetch": "^2.6.1",
162
167
  "npm-run-posix-or-windows": "^2.0.2",
163
168
  "pako": "^2.0.3",
164
- "preact": "^10.5.14",
169
+ "preact": "^10.7.2",
165
170
  "pretty-json-stringify": "^0.0.2",
166
171
  "puppeteer": "13.7.0",
167
172
  "resolve": "^1.20.0",
@@ -173,7 +178,7 @@
173
178
  "rollup-plugin-terser": "^7.0.2",
174
179
  "tabulator-tables": "^4.9.3",
175
180
  "terser": "^5.3.8",
176
- "ts-jest": "^27.0.4",
181
+ "testdouble": "^3.16.5",
177
182
  "typed-query-selector": "^2.6.1",
178
183
  "typescript": "^4.7.3",
179
184
  "wait-for-expect": "^3.0.2",
@@ -568,15 +568,16 @@ class Util {
568
568
  */
569
569
  Util.reportJson = null;
570
570
 
571
+ let svgSuffix = 0;
571
572
  /**
572
573
  * An always-increasing counter for making unique SVG ID suffixes.
573
574
  */
574
- Util.getUniqueSuffix = (() => {
575
- let svgSuffix = 0;
576
- return function() {
577
- return svgSuffix++;
578
- };
579
- })();
575
+ Util.getUniqueSuffix = () => {
576
+ return svgSuffix++;
577
+ };
578
+ Util.resetUniqueSuffix = () => {
579
+ svgSuffix = 0;
580
+ };
580
581
 
581
582
  /**
582
583
  * Report-renderer-specific strings.
@@ -6,6 +6,9 @@
6
6
 
7
7
  module.exports = {
8
8
  env: {
9
- jest: true,
9
+ mocha: true,
10
+ },
11
+ globals: {
12
+ expect: true,
10
13
  },
11
14
  };
@@ -7,7 +7,7 @@
7
7
  import fs from 'fs';
8
8
 
9
9
  import jsdom from 'jsdom';
10
- import {jest} from '@jest/globals';
10
+ import jestMock from 'jest-mock';
11
11
 
12
12
  import * as lighthouseRenderer from '../../clients/bundle.js';
13
13
  import {LH_ROOT} from '../../../root.js';
@@ -17,8 +17,8 @@ const sampleResultsStr =
17
17
 
18
18
  describe('lighthouseRenderer bundle', () => {
19
19
  let document;
20
- beforeAll(() => {
21
- global.console.warn = jest.fn();
20
+ before(() => {
21
+ global.console.warn = jestMock.fn();
22
22
 
23
23
  const {window} = new jsdom.JSDOM();
24
24
  document = window.document;
@@ -38,7 +38,7 @@ describe('lighthouseRenderer bundle', () => {
38
38
  };
39
39
  });
40
40
 
41
- afterAll(() => {
41
+ after(() => {
42
42
  global.window = global.self = undefined;
43
43
  global.HTMLInputElement = undefined;
44
44
  });
@@ -13,7 +13,9 @@ const fs = require('fs');
13
13
  const csvValidator = require('csv-validator');
14
14
 
15
15
  const ReportGenerator = require('../../generator/report-generator.js');
16
- const sampleResults = require('../../../lighthouse-core/test/results/sample_v2.json');
16
+ const {readJson} = require('../../../root.js');
17
+
18
+ const sampleResults = readJson('lighthouse-core/test/results/sample_v2.json');
17
19
 
18
20
  describe('ReportGenerator', () => {
19
21
  describe('#replaceStrings', () => {
@@ -13,7 +13,7 @@ import {I18n} from '../../renderer/i18n.js';
13
13
  import {DOM} from '../../renderer/dom.js';
14
14
  import {DetailsRenderer} from '../../renderer/details-renderer.js';
15
15
  import {CategoryRenderer} from '../../renderer/category-renderer.js';
16
- import {readJson} from '../../../root.js';
16
+ import {readJson} from '../../../lighthouse-core/test/test-utils.js';
17
17
 
18
18
  const sampleResultsOrig = readJson('../../../lighthouse-core/test/results/sample_v2.json', import.meta);
19
19
 
@@ -21,7 +21,7 @@ describe('CategoryRenderer', () => {
21
21
  let renderer;
22
22
  let sampleResults;
23
23
 
24
- beforeAll(() => {
24
+ before(() => {
25
25
  Util.i18n = new I18n('en', {...Util.UIStrings});
26
26
 
27
27
  const {document} = new jsdom.JSDOM().window;
@@ -32,7 +32,7 @@ describe('CategoryRenderer', () => {
32
32
  sampleResults = Util.prepareReportResult(sampleResultsOrig);
33
33
  });
34
34
 
35
- afterAll(() => {
35
+ after(() => {
36
36
  Util.i18n = undefined;
37
37
  });
38
38
 
@@ -7,7 +7,6 @@
7
7
  import fs from 'fs';
8
8
 
9
9
  import jsdom from 'jsdom';
10
- import expect from 'expect';
11
10
 
12
11
  import {DOM} from '../../renderer/dom.js';
13
12
  import {LH_ROOT} from '../../../root.js';
@@ -82,41 +81,44 @@ async function assertDOMTreeMatches(tmplEl) {
82
81
  }
83
82
  }
84
83
 
85
- const originalCreateElement = DOM.prototype.createElement;
86
- const originalCreateElementNS = DOM.prototype.createElementNS;
87
- beforeAll(() => {
88
- /**
89
- * @param {string} classNames
90
- */
91
- function checkPrefix(classNames) {
92
- if (!classNames) return;
93
-
94
- for (const className of classNames.split(' ')) {
95
- if (!className.startsWith('lh-')) {
96
- throw new Error(`expected classname to start with lh-, got: ${className}`);
84
+ describe('Components', () => {
85
+ const originalCreateElement = DOM.prototype.createElement;
86
+ const originalCreateElementNS = DOM.prototype.createElementNS;
87
+
88
+ before(() => {
89
+ /**
90
+ * @param {string} classNames
91
+ */
92
+ function checkPrefix(classNames) {
93
+ if (!classNames) return;
94
+
95
+ for (const className of classNames.split(' ')) {
96
+ if (!className.startsWith('lh-')) {
97
+ throw new Error(`expected classname to start with lh-, got: ${className}`);
98
+ }
97
99
  }
98
100
  }
99
- }
100
-
101
- DOM.prototype.createElement = function(...args) {
102
- const classNames = args[1];
103
- checkPrefix(classNames);
104
- return originalCreateElement.call(this, ...args);
105
- };
106
- DOM.prototype.createElementNS = function(...args) {
107
- const classNames = args[2];
108
- checkPrefix(classNames);
109
- return originalCreateElementNS.call(this, ...args);
110
- };
111
- });
112
101
 
113
- afterAll(() => {
114
- DOM.prototype.createElement = originalCreateElement;
115
- DOM.prototype.createElementNS = originalCreateElementNS;
116
- });
102
+ DOM.prototype.createElement = function(...args) {
103
+ const classNames = args[1];
104
+ checkPrefix(classNames);
105
+ return originalCreateElement.call(this, ...args);
106
+ };
107
+ DOM.prototype.createElementNS = function(...args) {
108
+ const classNames = args[2];
109
+ checkPrefix(classNames);
110
+ return originalCreateElementNS.call(this, ...args);
111
+ };
112
+ });
117
113
 
118
- for (const tmpEl of tmplEls) {
119
- it(`${tmpEl.id} component matches HTML source`, async () => {
120
- await assertDOMTreeMatches(tmpEl);
114
+ after(() => {
115
+ DOM.prototype.createElement = originalCreateElement;
116
+ DOM.prototype.createElementNS = originalCreateElementNS;
121
117
  });
122
- }
118
+
119
+ for (const tmpEl of tmplEls) {
120
+ it(`${tmpEl.id} component matches HTML source`, async () => {
121
+ await assertDOMTreeMatches(tmpEl);
122
+ });
123
+ }
124
+ });
@@ -72,7 +72,7 @@ describe('DetailsRenderer', () => {
72
72
  let dom;
73
73
  let detailsRenderer;
74
74
 
75
- beforeAll(() => {
75
+ before(() => {
76
76
  Util.i18n = new I18n('en', {...Util.UIStrings});
77
77
 
78
78
  const {document} = new jsdom.JSDOM().window;
@@ -80,7 +80,7 @@ describe('DetailsRenderer', () => {
80
80
  detailsRenderer = new DetailsRenderer(dom);
81
81
  });
82
82
 
83
- afterAll(() => {
83
+ after(() => {
84
84
  Util.i18n = undefined;
85
85
  });
86
86
 
@@ -22,12 +22,12 @@ describe('DetailsRenderer', () => {
22
22
  renderer = new DetailsRenderer(dom, options);
23
23
  }
24
24
 
25
- beforeAll(() => {
25
+ before(() => {
26
26
  Util.i18n = new I18n('en', {...Util.UIStrings});
27
27
  createRenderer();
28
28
  });
29
29
 
30
- afterAll(() => {
30
+ after(() => {
31
31
  Util.i18n = undefined;
32
32
  });
33
33
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  import {strict as assert} from 'assert';
8
8
 
9
- import {jest} from '@jest/globals';
9
+ import jestMock from 'jest-mock';
10
10
  import jsdom from 'jsdom';
11
11
 
12
12
  import {DOM} from '../../renderer/dom.js';
@@ -19,20 +19,20 @@ describe('DOM', () => {
19
19
  let window;
20
20
  let nativeCreateObjectURL;
21
21
 
22
- beforeAll(() => {
22
+ before(() => {
23
23
  Util.i18n = new I18n('en', {...Util.UIStrings});
24
24
  window = new jsdom.JSDOM().window;
25
25
 
26
26
  // The Node version of URL.createObjectURL isn't compatible with the jsdom blob type,
27
27
  // so we stub it.
28
28
  nativeCreateObjectURL = URL.createObjectURL;
29
- URL.createObjectURL = jest.fn(_ => `https://fake-origin/blahblah-blobid`);
29
+ URL.createObjectURL = jestMock.fn(_ => `https://fake-origin/blahblah-blobid`);
30
30
 
31
31
  dom = new DOM(window.document);
32
32
  dom.setLighthouseChannel('someChannel');
33
33
  });
34
34
 
35
- afterAll(() => {
35
+ after(() => {
36
36
  Util.i18n = undefined;
37
37
  URL.createObjectURL = nativeCreateObjectURL;
38
38
  });