lighthouse 8.5.1-dev.20210928 → 8.5.1-dev.20211002

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 (39) hide show
  1. package/flow-report/.eslintrc.cjs +49 -0
  2. package/flow-report/assets/styles.css +1 -0
  3. package/flow-report/jest.config.js +1 -1
  4. package/flow-report/package.json +4 -0
  5. package/flow-report/src/app.tsx +8 -5
  6. package/flow-report/src/header.tsx +5 -1
  7. package/flow-report/src/i18n/i18n.tsx +44 -0
  8. package/flow-report/src/i18n/localized-strings.js +11 -0
  9. package/flow-report/src/i18n/ui-strings.js +40 -0
  10. package/flow-report/src/sidebar/sidebar.tsx +10 -15
  11. package/flow-report/src/summary/category.tsx +21 -13
  12. package/flow-report/src/summary/summary.tsx +24 -10
  13. package/flow-report/src/topbar.tsx +4 -1
  14. package/flow-report/src/util.ts +7 -7
  15. package/flow-report/test/app-test.tsx +1 -12
  16. package/flow-report/test/header-test.tsx +7 -13
  17. package/flow-report/test/sample-flow.ts +17 -0
  18. package/flow-report/test/sidebar/flow-test.tsx +6 -12
  19. package/flow-report/test/sidebar/sidebar-test.tsx +7 -13
  20. package/flow-report/test/summary/category-test.tsx +22 -14
  21. package/flow-report/test/summary/summary-test.tsx +5 -13
  22. package/flow-report/test/util-test.tsx +1 -12
  23. package/flow-report/tsconfig.json +1 -0
  24. package/jest.config.js +0 -15
  25. package/lighthouse-core/fraggle-rock/api.js +10 -0
  26. package/lighthouse-core/fraggle-rock/user-flow.js +27 -3
  27. package/lighthouse-core/lib/i18n/i18n.js +13 -1
  28. package/lighthouse-core/lib/i18n/locales/en-US.json +45 -0
  29. package/lighthouse-core/lib/i18n/locales/en-XL.json +45 -0
  30. package/lighthouse-core/lib/i18n/swap-flow-locale.js +20 -0
  31. package/lighthouse-core/lib/stack-packs.js +1 -13
  32. package/package.json +11 -9
  33. package/readme.md +1 -1
  34. package/report/clients/psi.js +1 -0
  35. package/report/test/clients/psi-test.js +2 -3
  36. package/report/test/renderer/report-renderer-axe-test.js +86 -0
  37. package/report/test/renderer/report-renderer-test.js +0 -55
  38. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +5 -3
  39. package/third-party/chromium-synchronization/installability-errors-test.js +2 -1
@@ -4,22 +4,26 @@
4
4
  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
5
  */
6
6
 
7
- import fs from 'fs';
8
- import {dirname} from 'path';
9
- import {fileURLToPath} from 'url';
10
-
7
+ import {FunctionComponent} from 'preact';
11
8
  import {render} from '@testing-library/preact';
12
9
 
13
10
  import {SummaryTooltip} from '../../src/summary/category';
14
11
  import {Util} from '../../../report/renderer/util';
12
+ import {flowResult} from '../sample-flow';
13
+ import {I18nProvider} from '../../src/i18n/i18n';
14
+ import {FlowResultContext} from '../../src/util';
15
+
16
+ let wrapper: FunctionComponent;
15
17
 
16
- const flowResult: LH.FlowResult = JSON.parse(
17
- fs.readFileSync(
18
- // eslint-disable-next-line max-len
19
- `${dirname(fileURLToPath(import.meta.url))}/../../../lighthouse-core/test/fixtures/fraggle-rock/reports/sample-lhrs.json`,
20
- 'utf-8'
21
- )
22
- );
18
+ beforeEach(() => {
19
+ wrapper = ({children}) => (
20
+ <FlowResultContext.Provider value={flowResult}>
21
+ <I18nProvider>
22
+ {children}
23
+ </I18nProvider>
24
+ </FlowResultContext.Provider>
25
+ );
26
+ });
23
27
 
24
28
  describe('SummaryTooltip', () => {
25
29
  it('renders tooltip with rating', async () => {
@@ -28,7 +32,8 @@ describe('SummaryTooltip', () => {
28
32
  const category = reportResult.categories['seo'];
29
33
 
30
34
  const root = render(
31
- <SummaryTooltip category={category} gatherMode={reportResult.gatherMode}/>
35
+ <SummaryTooltip category={category} gatherMode={reportResult.gatherMode}/>,
36
+ {wrapper}
32
37
  );
33
38
 
34
39
  const rating = root.getByTestId('SummaryTooltip__rating');
@@ -43,7 +48,8 @@ describe('SummaryTooltip', () => {
43
48
  const category = reportResult.categories['performance'];
44
49
 
45
50
  const root = render(
46
- <SummaryTooltip category={category} gatherMode={reportResult.gatherMode}/>
51
+ <SummaryTooltip category={category} gatherMode={reportResult.gatherMode}/>,
52
+ {wrapper}
47
53
  );
48
54
 
49
55
  expect(() => root.getByTestId('SummaryTooltip__rating')).toThrow();
@@ -56,7 +62,9 @@ describe('SummaryTooltip', () => {
56
62
  const category = reportResult.categories['performance'];
57
63
 
58
64
  const root = render(
59
- <SummaryTooltip category={category} gatherMode={reportResult.gatherMode}/>
65
+ <SummaryTooltip category={category} gatherMode={reportResult.gatherMode}/>,
66
+ {wrapper}
67
+
60
68
  );
61
69
 
62
70
  const rating = root.getByTestId('SummaryTooltip__rating');
@@ -4,24 +4,14 @@
4
4
  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
5
  */
6
6
 
7
- import fs from 'fs';
8
- import {dirname} from 'path';
9
- import {fileURLToPath} from 'url';
10
-
11
7
  import {render} from '@testing-library/preact';
12
8
  import {FunctionComponent} from 'preact';
13
9
 
10
+ import {I18nProvider} from '../../src/i18n/i18n';
14
11
  import {SummaryHeader, SummaryFlowStep} from '../../src/summary/summary';
15
12
  import {FlowResultContext} from '../../src/util';
16
13
  import {ReportRendererProvider} from '../../src/wrappers/report-renderer';
17
-
18
- const flowResult: LH.FlowResult = JSON.parse(
19
- fs.readFileSync(
20
- // eslint-disable-next-line max-len
21
- `${dirname(fileURLToPath(import.meta.url))}/../../../lighthouse-core/test/fixtures/fraggle-rock/reports/sample-lhrs.json`,
22
- 'utf-8'
23
- )
24
- );
14
+ import {flowResult} from '../sample-flow';
25
15
 
26
16
  let wrapper: FunctionComponent;
27
17
 
@@ -29,7 +19,9 @@ beforeEach(() => {
29
19
  wrapper = ({children}) => (
30
20
  <FlowResultContext.Provider value={flowResult}>
31
21
  <ReportRendererProvider>
32
- {children}
22
+ <I18nProvider>
23
+ {children}
24
+ </I18nProvider>
33
25
  </ReportRendererProvider>
34
26
  </FlowResultContext.Provider>
35
27
  );
@@ -4,24 +4,13 @@
4
4
  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
5
  */
6
6
 
7
- import fs from 'fs';
8
- import {dirname} from 'path';
9
- import {fileURLToPath} from 'url';
10
-
11
7
  import {jest} from '@jest/globals';
12
8
  import {renderHook} from '@testing-library/preact-hooks';
13
9
  import {FunctionComponent} from 'preact';
14
10
  import {act} from 'preact/test-utils';
15
11
 
16
12
  import {FlowResultContext, useCurrentLhr} from '../src/util';
17
-
18
- const flowResult: LH.FlowResult = JSON.parse(
19
- fs.readFileSync(
20
- // eslint-disable-next-line max-len
21
- `${dirname(fileURLToPath(import.meta.url))}/../../lighthouse-core/test/fixtures/fraggle-rock/reports/sample-lhrs.json`,
22
- 'utf-8'
23
- )
24
- );
13
+ import {flowResult} from './sample-flow';
25
14
 
26
15
  let wrapper: FunctionComponent;
27
16
 
@@ -16,6 +16,7 @@
16
16
  {"path": "../report"},
17
17
  ],
18
18
  "include": [
19
+ "**/*.js",
19
20
  "**/*.ts",
20
21
  "**/*.tsx",
21
22
  "./types",
package/jest.config.js CHANGED
@@ -6,18 +6,6 @@
6
6
  'use strict';
7
7
 
8
8
  module.exports = {
9
- collectCoverage: false,
10
- coverageReporters: ['none'],
11
- collectCoverageFrom: [
12
- '**/lighthouse-core/**/*.js',
13
- '**/lighthouse-cli/**/*.js',
14
- '**/report/**/*.js',
15
- '**/lighthouse-viewer/**/*.js',
16
- ],
17
- coveragePathIgnorePatterns: [
18
- '/test/',
19
- '/scripts/',
20
- ],
21
9
  setupFilesAfterEnv: ['./lighthouse-core/test/test-utils.js'],
22
10
  testEnvironment: 'node',
23
11
  testMatch: [
@@ -26,12 +14,9 @@ module.exports = {
26
14
  '**/report/**/*-test.js',
27
15
  '**/lighthouse-core/test/fraggle-rock/**/*-test-pptr.js',
28
16
  '**/lighthouse-treemap/**/*-test.js',
29
- '**/lighthouse-treemap/**/*-test-pptr.js',
30
17
  '**/lighthouse-viewer/**/*-test.js',
31
- '**/lighthouse-viewer/**/*-test-pptr.js',
32
18
  '**/third-party/**/*-test.js',
33
19
  '**/clients/test/**/*-test.js',
34
- '**/docs/**/*.test.js',
35
20
  ],
36
21
  transform: {},
37
22
  prettierPath: null,
@@ -8,9 +8,19 @@
8
8
  const {snapshot} = require('./gather/snapshot-runner.js');
9
9
  const {startTimespan} = require('./gather/timespan-runner.js');
10
10
  const {navigation} = require('./gather/navigation-runner.js');
11
+ const UserFlow = require('./user-flow.js');
12
+
13
+ /**
14
+ * @param {import('puppeteer').Page} page
15
+ * @param {UserFlow.UserFlowOptions} [options]
16
+ */
17
+ async function startFlow(page, options) {
18
+ return new UserFlow(page, options);
19
+ }
11
20
 
12
21
  module.exports = {
13
22
  snapshot,
14
23
  startTimespan,
15
24
  navigation,
25
+ startFlow,
16
26
  };
@@ -6,7 +6,9 @@
6
6
  'use strict';
7
7
 
8
8
  const {generateFlowReportHtml} = require('../../report/generator/report-generator.js');
9
- const {navigation, startTimespan, snapshot} = require('./api.js');
9
+ const {snapshot} = require('./gather/snapshot-runner.js');
10
+ const {startTimespan} = require('./gather/timespan-runner.js');
11
+ const {navigation} = require('./gather/navigation-runner.js');
10
12
 
11
13
  /** @typedef {Parameters<snapshot>[0]} FrOptions */
12
14
  /** @typedef {Omit<FrOptions, 'page'>} UserFlowOptions */
@@ -49,6 +51,29 @@ class UserFlow {
49
51
  }
50
52
  }
51
53
 
54
+ /**
55
+ * @param {string} url
56
+ * @param {StepOptions=} stepOptions
57
+ */
58
+ _getNextNavigationOptions(url, stepOptions) {
59
+ const options = {url, ...this.options, ...stepOptions};
60
+
61
+ // On repeat navigations, we want to disable storage reset by default (i.e. it's not a cold load).
62
+ const isSubsequentNavigation = this.steps.some(step => step.lhr.gatherMode === 'navigation');
63
+ if (isSubsequentNavigation) {
64
+ const configContext = {...options.configContext};
65
+ const settingsOverrides = {...configContext.settingsOverrides};
66
+ if (settingsOverrides.disableStorageReset === undefined) {
67
+ settingsOverrides.disableStorageReset = true;
68
+ }
69
+
70
+ configContext.settingsOverrides = settingsOverrides;
71
+ options.configContext = configContext;
72
+ }
73
+
74
+ return options;
75
+ }
76
+
52
77
  /**
53
78
  * @param {string} url
54
79
  * @param {StepOptions=} stepOptions
@@ -56,8 +81,7 @@ class UserFlow {
56
81
  async navigate(url, stepOptions) {
57
82
  if (this.currentTimespan) throw Error('Timespan already in progress');
58
83
 
59
- const options = {url, ...this.options, ...stepOptions};
60
- const result = await navigation(options);
84
+ const result = await navigation(this._getNextNavigationOptions(url, stepOptions));
61
85
  if (!result) throw Error('Navigation returned undefined');
62
86
 
63
87
  const providedName = stepOptions && stepOptions.stepName;
@@ -350,7 +350,7 @@ function getRendererFormattedStrings(locale) {
350
350
  /** @type {Record<string, string>} */
351
351
  const strings = {};
352
352
  for (const icuMessageId of icuMessageIds) {
353
- const [filename, key] = icuMessageId.split(' | ');
353
+ const {filename, key} = getIcuMessageIdParts(icuMessageId);
354
354
  if (!filename.endsWith('util.js')) throw new Error(`Unexpected message: ${icuMessageId}`);
355
355
 
356
356
  strings[key] = localeMessages[icuMessageId].message;
@@ -524,6 +524,17 @@ function isStringOrIcuMessage(value) {
524
524
  return typeof value === 'string' || isIcuMessage(value);
525
525
  }
526
526
 
527
+ /**
528
+ * @param {string} i18nMessageId
529
+ */
530
+ function getIcuMessageIdParts(i18nMessageId) {
531
+ if (!MESSAGE_I18N_ID_REGEX.test(i18nMessageId)) {
532
+ throw Error(`"${i18nMessageId}" does not appear to be a valid ICU message id`);
533
+ }
534
+ const [filename, key] = i18nMessageId.split(' | ');
535
+ return {filename, key};
536
+ }
537
+
527
538
  module.exports = {
528
539
  _formatPathAsString,
529
540
  UIStrings,
@@ -538,4 +549,5 @@ module.exports = {
538
549
  isStringOrIcuMessage,
539
550
  // TODO: exported for backwards compatibility. Consider removing on future breaking change.
540
551
  createMessageInstanceIdFn: createIcuMessageFn,
552
+ getIcuMessageIdParts,
541
553
  };
@@ -1,4 +1,49 @@
1
1
  {
2
+ "flow-report/src/i18n/ui-strings.js | allReports": {
3
+ "message": "All Reports"
4
+ },
5
+ "flow-report/src/i18n/ui-strings.js | desktop": {
6
+ "message": "Desktop"
7
+ },
8
+ "flow-report/src/i18n/ui-strings.js | mobile": {
9
+ "message": "Mobile"
10
+ },
11
+ "flow-report/src/i18n/ui-strings.js | navigationDescription": {
12
+ "message": "Page load"
13
+ },
14
+ "flow-report/src/i18n/ui-strings.js | navigationReport": {
15
+ "message": "Navigation report"
16
+ },
17
+ "flow-report/src/i18n/ui-strings.js | ratingAverage": {
18
+ "message": "Average"
19
+ },
20
+ "flow-report/src/i18n/ui-strings.js | ratingError": {
21
+ "message": "Error"
22
+ },
23
+ "flow-report/src/i18n/ui-strings.js | ratingFail": {
24
+ "message": "Poor"
25
+ },
26
+ "flow-report/src/i18n/ui-strings.js | ratingPass": {
27
+ "message": "Good"
28
+ },
29
+ "flow-report/src/i18n/ui-strings.js | snapshotDescription": {
30
+ "message": "Captured state of page"
31
+ },
32
+ "flow-report/src/i18n/ui-strings.js | snapshotReport": {
33
+ "message": "Snapshot report"
34
+ },
35
+ "flow-report/src/i18n/ui-strings.js | summary": {
36
+ "message": "Summary"
37
+ },
38
+ "flow-report/src/i18n/ui-strings.js | timespanDescription": {
39
+ "message": "User interactions"
40
+ },
41
+ "flow-report/src/i18n/ui-strings.js | timespanReport": {
42
+ "message": "Timespan report"
43
+ },
44
+ "flow-report/src/i18n/ui-strings.js | title": {
45
+ "message": "Lighthouse User Flow Report"
46
+ },
2
47
  "lighthouse-core/audits/accessibility/accesskeys.js | description": {
3
48
  "message": "Access keys let users quickly focus a part of the page. For proper navigation, each access key must be unique. [Learn more](https://web.dev/accesskeys/)."
4
49
  },
@@ -1,4 +1,49 @@
1
1
  {
2
+ "flow-report/src/i18n/ui-strings.js | allReports": {
3
+ "message": "Âĺl̂ Ŕêṕôŕt̂ś"
4
+ },
5
+ "flow-report/src/i18n/ui-strings.js | desktop": {
6
+ "message": "D̂éŝḱt̂óp̂"
7
+ },
8
+ "flow-report/src/i18n/ui-strings.js | mobile": {
9
+ "message": "M̂ób̂íl̂é"
10
+ },
11
+ "flow-report/src/i18n/ui-strings.js | navigationDescription": {
12
+ "message": "P̂áĝé l̂óâd́"
13
+ },
14
+ "flow-report/src/i18n/ui-strings.js | navigationReport": {
15
+ "message": "N̂áv̂íĝát̂íôń r̂ép̂ór̂t́"
16
+ },
17
+ "flow-report/src/i18n/ui-strings.js | ratingAverage": {
18
+ "message": "Âv́êŕâǵê"
19
+ },
20
+ "flow-report/src/i18n/ui-strings.js | ratingError": {
21
+ "message": "Êŕr̂ór̂"
22
+ },
23
+ "flow-report/src/i18n/ui-strings.js | ratingFail": {
24
+ "message": "P̂óôŕ"
25
+ },
26
+ "flow-report/src/i18n/ui-strings.js | ratingPass": {
27
+ "message": "Ĝóôd́"
28
+ },
29
+ "flow-report/src/i18n/ui-strings.js | snapshotDescription": {
30
+ "message": "Ĉáp̂t́ûŕêd́ ŝt́ât́ê óf̂ ṕâǵê"
31
+ },
32
+ "flow-report/src/i18n/ui-strings.js | snapshotReport": {
33
+ "message": "Ŝńâṕŝh́ôt́ r̂ép̂ór̂t́"
34
+ },
35
+ "flow-report/src/i18n/ui-strings.js | summary": {
36
+ "message": "Ŝúm̂ḿâŕŷ"
37
+ },
38
+ "flow-report/src/i18n/ui-strings.js | timespanDescription": {
39
+ "message": "Ûśêŕ îńt̂ér̂áĉt́îón̂ś"
40
+ },
41
+ "flow-report/src/i18n/ui-strings.js | timespanReport": {
42
+ "message": "T̂ím̂éŝṕâń r̂ép̂ór̂t́"
43
+ },
44
+ "flow-report/src/i18n/ui-strings.js | title": {
45
+ "message": "L̂íĝh́t̂h́ôúŝé Ûśêŕ F̂ĺôẃ R̂ép̂ór̂t́"
46
+ },
2
47
  "lighthouse-core/audits/accessibility/accesskeys.js | description": {
3
48
  "message": "Âćĉéŝś k̂éŷś l̂ét̂ úŝér̂ś q̂úîćk̂ĺŷ f́ôćûś â ṕâŕt̂ óf̂ t́ĥé p̂áĝé. F̂ór̂ ṕr̂óp̂ér̂ ńâv́îǵât́îón̂, éâćĥ áĉćêśŝ ḱêý m̂úŝt́ b̂é ûńîq́ûé. [L̂éâŕn̂ ḿôŕê](https://web.dev/accesskeys/)."
4
49
  },
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @license Copyright 2021 The Lighthouse Authors. All Rights Reserved.
3
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
+ */
6
+ 'use strict';
7
+
8
+ const swapLocale = require('./swap-locale.js');
9
+
10
+ /**
11
+ * @param {LH.FlowResult} flowResult
12
+ * @param {LH.Locale} locale
13
+ */
14
+ module.exports = function swapFlowLocale(flowResult, locale) {
15
+ const localizedFlowResult = JSON.parse(JSON.stringify(flowResult));
16
+ localizedFlowResult.steps = flowResult.steps.map(step => {
17
+ return {...step, lhr: swapLocale(step.lhr, locale).lhr};
18
+ });
19
+ return localizedFlowResult;
20
+ };
@@ -9,18 +9,6 @@ const log = require('lighthouse-logger');
9
9
  const stackPacks = require('lighthouse-stack-packs');
10
10
  const i18n = require('./i18n/i18n.js');
11
11
 
12
- /**
13
- * Resolve a module on web and node
14
- * @param {string} module
15
- */
16
- function resolve(module) {
17
- if (!require.resolve) {
18
- return `node_modules/${module}`;
19
- }
20
-
21
- return require.resolve(module);
22
- }
23
-
24
12
  /**
25
13
  * Pairs consisting of a stack pack's ID and the set of stacks needed to be
26
14
  * detected in a page to display that pack's advice.
@@ -87,7 +75,7 @@ function getStackPacks(pageStacks) {
87
75
 
88
76
  // Create i18n handler to get translated strings.
89
77
  const str_ = i18n.createMessageInstanceIdFn(
90
- resolve(`lighthouse-stack-packs/packs/${matchedPack.id}`),
78
+ `node_modules/lighthouse-stack-packs/packs/${matchedPack.id}.js`,
91
79
  matchedPack.UIStrings
92
80
  );
93
81
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lighthouse",
3
- "version": "8.5.1-dev.20210928",
3
+ "version": "8.5.1-dev.20211002",
4
4
  "description": "Automated auditing, performance metrics, and best practices for the web.",
5
5
  "main": "./lighthouse-core/index.js",
6
6
  "bin": {
@@ -9,7 +9,7 @@
9
9
  "smokehouse": "./lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js"
10
10
  },
11
11
  "engines": {
12
- "node": ">=12.13.0"
12
+ "node": ">=12.20.0 && 12.* || >=14.13 && 14.* || >=15"
13
13
  },
14
14
  "scripts": {
15
15
  "build-all": "npm-run-posix-or-windows build-all:task",
@@ -37,12 +37,12 @@
37
37
  "jest": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js",
38
38
  "test": "yarn diff:sample-json && yarn lint --quiet && yarn unit && yarn type-check",
39
39
  "test-bundle": "yarn smoke --runner bundle -j=1 --retries=2 --invert-match forms",
40
- "test-clients": "yarn jest \"$PWD/clients/\"",
41
- "test-viewer": "yarn unit-viewer && yarn jest lighthouse-viewer/test/viewer-test-pptr.js",
42
- "test-treemap": "yarn unit-treemap && yarn jest lighthouse-treemap/test/treemap-test-pptr.js",
40
+ "test-clients": "yarn jest \"$PWD/clients/\" && yarn jest --testMatch=\"**/clients/test/**/*-test-pptr.js\"",
41
+ "test-viewer": "yarn unit-viewer && yarn jest --testMatch=\"**/lighthouse-viewer/**/*-test-pptr.js\"",
42
+ "test-treemap": "yarn unit-treemap && yarn jest --testMatch=\"**/lighthouse-treemap/**/*-test-pptr.js\"",
43
43
  "test-lantern": "bash lighthouse-core/scripts/test-lantern.sh",
44
44
  "test-legacy-javascript": "bash lighthouse-core/scripts/test-legacy-javascript.sh",
45
- "test-docs": "yarn --cwd docs/recipes/auth && yarn jest docs/recipes/integration-test && yarn --cwd docs/recipes/custom-gatherer-puppeteer test",
45
+ "test-docs": "yarn --cwd docs/recipes/ test",
46
46
  "test-proto": "yarn compile-proto && yarn build-proto-roundtrip",
47
47
  "unit-core": "yarn jest \"lighthouse-core\"",
48
48
  "unit-cli": "yarn jest \"lighthouse-cli/\"",
@@ -50,8 +50,8 @@
50
50
  "unit-treemap": "yarn jest \"lighthouse-treemap/.*-test.js\"",
51
51
  "unit-viewer": "yarn jest \"lighthouse-viewer/.*-test.js\"",
52
52
  "unit-flow": "yarn jest \"flow-report/.*-test.[tj]s[x]?\"",
53
- "unit": "yarn unit-core && yarn unit-cli && yarn unit-report && yarn unit-viewer && yarn unit-treemap && yarn unit-flow",
54
- "unit:ci": "NODE_OPTIONS=--max-old-space-size=8192 npm run unit-core -- --ci && npm run unit-cli -- --ci && npm run unit-report -- --ci && npm run unit-viewer -- --ci && npm run unit-treemap -- --ci && npm run unit-flow -- --ci",
53
+ "unit": "yarn jest",
54
+ "unit:ci": "NODE_OPTIONS=--max-old-space-size=8192 npm run jest -- --ci",
55
55
  "core-unit": "yarn unit-core",
56
56
  "cli-unit": "yarn unit-cli",
57
57
  "viewer-unit": "yarn unit-viewer",
@@ -74,6 +74,7 @@
74
74
  "update:lantern-baseline": "node lighthouse-core/scripts/lantern/update-baseline-lantern-values.js",
75
75
  "update:sample-artifacts": "node lighthouse-core/scripts/update-report-fixtures.js",
76
76
  "update:sample-json": "yarn i18n:collect-strings && node ./lighthouse-cli -A=./lighthouse-core/test/results/artifacts --config-path=./lighthouse-core/test/results/sample-config.js --output=json --output-path=./lighthouse-core/test/results/sample_v2.json && node lighthouse-core/scripts/cleanup-LHR-for-diff.js ./lighthouse-core/test/results/sample_v2.json --only-remove-timing",
77
+ "update:flow-sample-json": "node ./lighthouse-core/scripts/update-flow-fixtures.js",
77
78
  "update:test-devtools": "bash lighthouse-core/test/chromium-web-tests/test-locally.sh --reset-results",
78
79
  "test-devtools": "bash lighthouse-core/test/chromium-web-tests/test-locally.sh",
79
80
  "open-devtools": "bash lighthouse-core/scripts/open-devtools.sh",
@@ -88,7 +89,8 @@
88
89
  "serve-dist": "cd dist && python -m SimpleHTTPServer",
89
90
  "serve-gh-pages": "cd dist/gh-pages && python -m SimpleHTTPServer",
90
91
  "serve-treemap": "yarn serve-gh-pages",
91
- "serve-viewer": "yarn serve-gh-pages"
92
+ "serve-viewer": "yarn serve-gh-pages",
93
+ "flow-report": "yarn build-report --flow && node ./lighthouse-core/scripts/build-test-flow-report.js"
92
94
  },
93
95
  "devDependencies": {
94
96
  "@build-tracker/cli": "^1.0.0-beta.15",
package/readme.md CHANGED
@@ -52,7 +52,7 @@ The Chrome extension was available prior to Lighthouse being available in Chrome
52
52
 
53
53
  The Node CLI provides the most flexibility in how Lighthouse runs can be configured and reported. Users who want more advanced usage, or want to run Lighthouse in an automated fashion should use the Node CLI.
54
54
 
55
- _Lighthouse requires Node 12 LTS (12.x) or later._
55
+ _Lighthouse requires Node 12 LTS (12.20) or later._
56
56
 
57
57
  **Installation**:
58
58
 
@@ -77,6 +77,7 @@ export function prepareLabData(LHResult, document) {
77
77
  reportLHR.categoryGroups,
78
78
  {environment: 'PSI', gatherMode: lhResult.gatherMode}
79
79
  );
80
+ perfCategoryEl.append(dom.createComponent('styles'));
80
81
 
81
82
  const scoreGaugeEl = dom.find('.lh-score__gauge', perfCategoryEl);
82
83
  scoreGaugeEl.remove();
@@ -67,8 +67,6 @@ describe('PSI', () => {
67
67
  // Check that the report exists and has some content.
68
68
  assert.ok(result.perfCategoryEl instanceof document.defaultView.Element);
69
69
  assert.ok(result.perfCategoryEl.outerHTML.length > 50000, 'perfCategory HTML is populated');
70
- assert.ok(!result.perfCategoryEl.outerHTML.includes('lh-permalink'),
71
- 'PSI\'s perfCategory HTML doesn\'t include a lh-permalink element');
72
70
  // Assume using default locale.
73
71
  const title = result.perfCategoryEl.querySelector('.lh-audit-group--metrics')
74
72
  .querySelector('.lh-audit-group__title').textContent;
@@ -83,7 +81,8 @@ describe('PSI', () => {
83
81
 
84
82
  assert.ok(result.perfCategoryEl instanceof document.defaultView.Element);
85
83
  assert.ok(result.perfCategoryEl.outerHTML.length > 50000, 'perfCategory HTML is populated');
86
- assert.ok(!result.perfCategoryEl.outerHTML.includes('lh-permalink'),
84
+ // styles for .lh-permalink are ok, but not the HTML
85
+ assert.ok(!result.perfCategoryEl.outerHTML.includes('class="lh-permalink'),
87
86
  'PSI\'s perfCategory HTML doesn\'t include a lh-permalink element');
88
87
 
89
88
  assert.equal(typeof result.finalScreenshotDataUri, 'string');
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @license Copyright 2021 The Lighthouse Authors. All Rights Reserved.
3
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
+ */
6
+ 'use strict';
7
+
8
+ /* eslint-env jest */
9
+
10
+ import jsdom from 'jsdom';
11
+
12
+ import {Util} from '../../renderer/util.js';
13
+ import {DOM} from '../../renderer/dom.js';
14
+ import {DetailsRenderer} from '../../renderer/details-renderer.js';
15
+ import {CategoryRenderer} from '../../renderer/category-renderer.js';
16
+ import {ReportRenderer} from '../../renderer/report-renderer.js';
17
+ import sampleResultsOrig from '../../../lighthouse-core/test/results/sample_v2.json';
18
+
19
+ describe('ReportRendererAxe', () => {
20
+ describe('with aXe', () => {
21
+ let axe;
22
+ let renderer;
23
+ let sampleResults;
24
+
25
+ beforeAll(async () => {
26
+ const {window} = new jsdom.JSDOM();
27
+ const dom = new DOM(window.document);
28
+ const detailsRenderer = new DetailsRenderer(dom);
29
+ const categoryRenderer = new CategoryRenderer(dom, detailsRenderer);
30
+ renderer = new ReportRenderer(dom, categoryRenderer);
31
+ sampleResults = Util.prepareReportResult(sampleResultsOrig);
32
+
33
+ // Needed by axe-core
34
+ // https://github.com/dequelabs/axe-core/blob/581c441c/doc/examples/jsdom/test/a11y.js#L24
35
+ global.window = global.self = window;
36
+ global.Node = global.self.Node;
37
+ global.Element = global.self.Element;
38
+
39
+ // axe-core must be imported after the global polyfills
40
+ axe = (await import('axe-core')).default;
41
+ });
42
+
43
+ afterAll(() => {
44
+ global.window = undefined;
45
+ global.Node = undefined;
46
+ global.Element = undefined;
47
+ });
48
+
49
+ it('renders without axe violations', () => {
50
+ const container = renderer._dom._document.createElement('main');
51
+ const output = renderer.renderReport(sampleResults, container);
52
+
53
+ renderer._dom._document.body.appendChild(container);
54
+
55
+ const config = {
56
+ rules: {
57
+ // Reports may have duplicate ids
58
+ // https://github.com/GoogleChrome/lighthouse/issues/9432
59
+ 'duplicate-id': {enabled: false},
60
+ 'duplicate-id-aria': {enabled: false},
61
+ 'landmark-no-duplicate-contentinfo': {enabled: false},
62
+ // The following rules are disable for axe-core + jsdom compatibility
63
+ // https://github.com/dequelabs/axe-core/tree/b573b1c1/doc/examples/jest_react#to-run-the-example
64
+ 'color-contrast': {enabled: false},
65
+ 'link-in-text-block': {enabled: false},
66
+ // Report has empty links prior to i18n-ing.
67
+ 'link-name': {enabled: false},
68
+ // May not be a real issue. https://github.com/dequelabs/axe-core/issues/2958
69
+ 'nested-interactive': {enabled: false},
70
+ },
71
+ };
72
+
73
+ return new Promise(resolve => {
74
+ axe.run(output, config, (error, {violations}) => {
75
+ expect(error).toBeNull();
76
+ expect(violations).toEqual([]);
77
+ resolve();
78
+ });
79
+ });
80
+ // This test takes 40s on fast hardware, and 50-60s on GHA.
81
+ // https://github.com/dequelabs/axe-core/tree/b573b1c1/doc/examples/jest_react#timeout-issues
82
+ },
83
+ /* timeout= */ 100 * 1000
84
+ );
85
+ });
86
+ });