lighthouse 12.2.0 → 12.2.1

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 (79) hide show
  1. package/cli/test/smokehouse/lighthouse-runners/bundle.d.ts +4 -3
  2. package/cli/test/smokehouse/lighthouse-runners/bundle.js +16 -9
  3. package/cli/test/smokehouse/lighthouse-runners/cli.d.ts +4 -3
  4. package/cli/test/smokehouse/lighthouse-runners/cli.js +26 -32
  5. package/cli/test/smokehouse/lighthouse-runners/devtools.d.ts +3 -3
  6. package/cli/test/smokehouse/lighthouse-runners/devtools.js +8 -5
  7. package/cli/test/smokehouse/smokehouse.js +6 -1
  8. package/core/audits/accessibility/accesskeys.js +1 -1
  9. package/core/audits/accessibility/aria-allowed-attr.js +1 -1
  10. package/core/audits/accessibility/aria-allowed-role.js +1 -1
  11. package/core/audits/accessibility/aria-command-name.js +1 -1
  12. package/core/audits/accessibility/aria-conditional-attr.js +1 -1
  13. package/core/audits/accessibility/aria-deprecated-role.js +1 -1
  14. package/core/audits/accessibility/aria-dialog-name.js +1 -1
  15. package/core/audits/accessibility/aria-hidden-body.js +1 -1
  16. package/core/audits/accessibility/aria-hidden-focus.js +1 -1
  17. package/core/audits/accessibility/aria-input-field-name.js +1 -1
  18. package/core/audits/accessibility/aria-meter-name.js +1 -1
  19. package/core/audits/accessibility/aria-progressbar-name.js +1 -1
  20. package/core/audits/accessibility/aria-prohibited-attr.js +1 -1
  21. package/core/audits/accessibility/aria-required-attr.js +1 -1
  22. package/core/audits/accessibility/aria-required-children.js +1 -1
  23. package/core/audits/accessibility/aria-required-parent.js +1 -1
  24. package/core/audits/accessibility/aria-roles.js +1 -1
  25. package/core/audits/accessibility/aria-text.js +1 -1
  26. package/core/audits/accessibility/aria-toggle-field-name.js +1 -1
  27. package/core/audits/accessibility/aria-tooltip-name.js +1 -1
  28. package/core/audits/accessibility/aria-treeitem-name.js +1 -1
  29. package/core/audits/accessibility/aria-valid-attr-value.js +1 -1
  30. package/core/audits/accessibility/aria-valid-attr.js +1 -1
  31. package/core/audits/accessibility/button-name.js +1 -1
  32. package/core/audits/accessibility/bypass.js +1 -1
  33. package/core/audits/accessibility/color-contrast.js +1 -1
  34. package/core/audits/accessibility/definition-list.js +1 -1
  35. package/core/audits/accessibility/dlitem.js +1 -1
  36. package/core/audits/accessibility/document-title.js +1 -1
  37. package/core/audits/accessibility/duplicate-id-aria.js +1 -1
  38. package/core/audits/accessibility/empty-heading.js +1 -1
  39. package/core/audits/accessibility/form-field-multiple-labels.js +1 -1
  40. package/core/audits/accessibility/frame-title.js +1 -1
  41. package/core/audits/accessibility/heading-order.js +1 -1
  42. package/core/audits/accessibility/html-has-lang.js +1 -1
  43. package/core/audits/accessibility/html-lang-valid.js +1 -1
  44. package/core/audits/accessibility/html-xml-lang-mismatch.js +1 -1
  45. package/core/audits/accessibility/identical-links-same-purpose.js +1 -1
  46. package/core/audits/accessibility/image-alt.js +1 -1
  47. package/core/audits/accessibility/image-redundant-alt.js +1 -1
  48. package/core/audits/accessibility/input-button-name.js +1 -1
  49. package/core/audits/accessibility/input-image-alt.js +1 -1
  50. package/core/audits/accessibility/label-content-name-mismatch.js +1 -1
  51. package/core/audits/accessibility/label.js +1 -1
  52. package/core/audits/accessibility/landmark-one-main.js +1 -1
  53. package/core/audits/accessibility/link-in-text-block.js +1 -1
  54. package/core/audits/accessibility/link-name.js +1 -1
  55. package/core/audits/accessibility/list.js +1 -1
  56. package/core/audits/accessibility/listitem.js +1 -1
  57. package/core/audits/accessibility/meta-refresh.js +1 -1
  58. package/core/audits/accessibility/meta-viewport.js +1 -1
  59. package/core/audits/accessibility/object-alt.js +1 -1
  60. package/core/audits/accessibility/select-name.js +1 -1
  61. package/core/audits/accessibility/skip-link.js +1 -1
  62. package/core/audits/accessibility/tabindex.js +1 -1
  63. package/core/audits/accessibility/table-duplicate-name.js +1 -1
  64. package/core/audits/accessibility/table-fake-caption.js +1 -1
  65. package/core/audits/accessibility/target-size.js +1 -1
  66. package/core/audits/accessibility/td-has-header.js +1 -1
  67. package/core/audits/accessibility/td-headers-attr.js +1 -1
  68. package/core/audits/accessibility/th-has-data-cells.js +1 -1
  69. package/core/audits/accessibility/valid-lang.js +1 -1
  70. package/core/audits/accessibility/video-caption.js +1 -1
  71. package/core/audits/byte-efficiency/uses-text-compression.js +12 -6
  72. package/core/audits/third-party-cookies.js +1 -1
  73. package/core/gather/gatherers/accessibility.js +2 -0
  74. package/core/lib/third-party-web.d.ts +7 -0
  75. package/core/lib/third-party-web.js +13 -1
  76. package/package.json +4 -4
  77. package/shared/localization/locales/en-US.json +64 -64
  78. package/shared/localization/locales/en-XL.json +64 -64
  79. package/types/internal/smokehouse.d.ts +2 -1
@@ -2,12 +2,13 @@
2
2
  * Launch Chrome and do a full Lighthouse run via the Lighthouse DevTools bundle.
3
3
  * @param {string} url
4
4
  * @param {LH.Config=} config
5
+ * @param {LocalConsole=} logger
5
6
  * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
6
- * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
7
+ * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts}>}
7
8
  */
8
- export function runLighthouse(url: string, config?: LH.Config | undefined, testRunnerOptions?: Smokehouse.SmokehouseOptions["testRunnerOptions"] | undefined): Promise<{
9
+ export function runLighthouse(url: string, config?: LH.Config | undefined, logger?: LocalConsole | undefined, testRunnerOptions?: Smokehouse.SmokehouseOptions["testRunnerOptions"] | undefined): Promise<{
9
10
  lhr: LH.Result;
10
11
  artifacts: LH.Artifacts;
11
- log: string;
12
12
  }>;
13
+ import { LocalConsole } from '../lib/local-console.js';
13
14
  //# sourceMappingURL=bundle.d.ts.map
@@ -18,9 +18,11 @@ import {once} from 'events';
18
18
 
19
19
  import puppeteer from 'puppeteer-core';
20
20
  import * as ChromeLauncher from 'chrome-launcher';
21
+ import thirdPartyWebLib from 'third-party-web/nostats-subset.js';
21
22
 
22
23
  import {LH_ROOT} from '../../../../shared/root.js';
23
24
  import {loadArtifacts, saveArtifacts} from '../../../../core/lib/asset-saver.js';
25
+ import {LocalConsole} from '../lib/local-console.js';
24
26
 
25
27
  // This runs only in the worker. The rest runs on the main thread.
26
28
  if (!isMainThread && parentPort) {
@@ -73,6 +75,11 @@ async function runBundledLighthouse(url, config, testRunnerOptions) {
73
75
  // @ts-expect-error - not worth giving test global an actual type.
74
76
  const lighthouse = global.runBundledLighthouse;
75
77
 
78
+ /** @type {import('../../../../core/lib/third-party-web.js')['default']} */
79
+ // @ts-expect-error
80
+ const thirdPartyWeb = global.thirdPartyWeb;
81
+ thirdPartyWeb.provideThirdPartyWeb(thirdPartyWebLib);
82
+
76
83
  // Launch and connect to Chrome.
77
84
  const launchedChrome = await ChromeLauncher.launch({
78
85
  chromeFlags: [
@@ -105,12 +112,13 @@ async function runBundledLighthouse(url, config, testRunnerOptions) {
105
112
  * Launch Chrome and do a full Lighthouse run via the Lighthouse DevTools bundle.
106
113
  * @param {string} url
107
114
  * @param {LH.Config=} config
115
+ * @param {LocalConsole=} logger
108
116
  * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
109
- * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
117
+ * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts}>}
110
118
  */
111
- async function runLighthouse(url, config, testRunnerOptions = {}) {
112
- /** @type {string[]} */
113
- const logs = [];
119
+ async function runLighthouse(url, config, logger, testRunnerOptions = {}) {
120
+ logger = logger || new LocalConsole();
121
+
114
122
  const worker = new Worker(new URL(import.meta.url), {
115
123
  stdout: true,
116
124
  stderr: true,
@@ -119,16 +127,16 @@ async function runLighthouse(url, config, testRunnerOptions = {}) {
119
127
  worker.stdout.setEncoding('utf8');
120
128
  worker.stderr.setEncoding('utf8');
121
129
  worker.stdout.addListener('data', (data) => {
122
- logs.push(`[STDOUT] ${data}`);
130
+ logger.log(`[STDOUT] ${data}`);
123
131
  });
124
132
  worker.stderr.addListener('data', (data) => {
125
- logs.push(`[STDERR] ${data}`);
133
+ logger.log(`[STDERR] ${data}`);
126
134
  });
127
135
  const [workerResponse] = await once(worker, 'message');
128
- const log = logs.join('') + '\n';
129
136
 
130
137
  if (workerResponse.type === 'error') {
131
- throw new Error(`Worker returned an error: ${workerResponse.value}\nLog:\n${log}`);
138
+ const log = logger.getLog();
139
+ throw new Error(`Worker returned an error: ${workerResponse.value}\nLog:\n${log}\n`);
132
140
  }
133
141
 
134
142
  const result = workerResponse.value;
@@ -142,7 +150,6 @@ async function runLighthouse(url, config, testRunnerOptions = {}) {
142
150
  return {
143
151
  lhr: result.lhr,
144
152
  artifacts,
145
- log,
146
153
  };
147
154
  }
148
155
 
@@ -2,12 +2,13 @@
2
2
  * Launch Chrome and do a full Lighthouse run via the Lighthouse CLI.
3
3
  * @param {string} url
4
4
  * @param {LH.Config=} config
5
+ * @param {LocalConsole=} logger
5
6
  * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
6
- * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
7
+ * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts}>}
7
8
  */
8
- export function runLighthouse(url: string, config?: LH.Config | undefined, testRunnerOptions?: Smokehouse.SmokehouseOptions["testRunnerOptions"] | undefined): Promise<{
9
+ export function runLighthouse(url: string, config?: LH.Config | undefined, logger?: LocalConsole | undefined, testRunnerOptions?: Smokehouse.SmokehouseOptions["testRunnerOptions"] | undefined): Promise<{
9
10
  lhr: LH.Result;
10
11
  artifacts: LH.Artifacts;
11
- log: string;
12
12
  }>;
13
+ import { LocalConsole } from '../lib/local-console.js';
13
14
  //# sourceMappingURL=cli.d.ts.map
@@ -12,8 +12,7 @@
12
12
  */
13
13
 
14
14
  import {promises as fs} from 'fs';
15
- import {promisify} from 'util';
16
- import {execFile} from 'child_process';
15
+ import {spawn} from 'child_process';
17
16
 
18
17
  import log from 'lighthouse-logger';
19
18
 
@@ -22,21 +21,20 @@ import {LocalConsole} from '../lib/local-console.js';
22
21
  import {ChildProcessError} from '../lib/child-process-error.js';
23
22
  import {LH_ROOT} from '../../../../shared/root.js';
24
23
 
25
- const execFileAsync = promisify(execFile);
26
-
27
24
  /**
28
25
  * Launch Chrome and do a full Lighthouse run via the Lighthouse CLI.
29
26
  * @param {string} url
30
27
  * @param {LH.Config=} config
28
+ * @param {LocalConsole=} logger
31
29
  * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
32
- * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
30
+ * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts}>}
33
31
  */
34
- async function runLighthouse(url, config, testRunnerOptions = {}) {
32
+ async function runLighthouse(url, config, logger, testRunnerOptions = {}) {
35
33
  const {isDebug} = testRunnerOptions;
36
34
  const tmpDir = `${LH_ROOT}/.tmp/smokehouse`;
37
35
  await fs.mkdir(tmpDir, {recursive: true});
38
36
  const tmpPath = await fs.mkdtemp(`${tmpDir}/smokehouse-`);
39
- return internalRun(url, tmpPath, config, testRunnerOptions)
37
+ return internalRun(url, tmpPath, config, logger, testRunnerOptions)
40
38
  // Wait for internalRun() before removing scratch directory.
41
39
  .finally(() => !isDebug && fs.rm(tmpPath, {recursive: true, force: true}));
42
40
  }
@@ -46,12 +44,13 @@ async function runLighthouse(url, config, testRunnerOptions = {}) {
46
44
  * @param {string} url
47
45
  * @param {string} tmpPath
48
46
  * @param {LH.Config=} config
47
+ * @param {LocalConsole=} logger
49
48
  * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} options
50
- * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
49
+ * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts}>}
51
50
  */
52
- async function internalRun(url, tmpPath, config, options) {
51
+ async function internalRun(url, tmpPath, config, logger, options) {
53
52
  const {isDebug, headless} = options || {};
54
- const localConsole = new LocalConsole();
53
+ logger = logger || new LocalConsole();
55
54
 
56
55
  const outputPath = `${tmpPath}/smokehouse.report.json`;
57
56
  const artifactsDirectory = `${tmpPath}/artifacts/`;
@@ -78,29 +77,25 @@ async function internalRun(url, tmpPath, config, options) {
78
77
 
79
78
  const command = 'node';
80
79
  const env = {...process.env, NODE_ENV: 'test'};
81
- localConsole.log(`${log.dim}$ ${command} ${args.join(' ')} ${log.reset}`);
82
-
83
- /** @type {{stdout: string, stderr: string, code?: number}} */
84
- let execResult;
85
- try {
86
- execResult = await execFileAsync(command, args, {env});
87
- } catch (e) {
88
- // exec-thrown errors have stdout, stderr, and exit code from child process.
89
- execResult = e;
90
- }
91
-
92
- const exitCode = execResult.code || 0;
93
- if (isDebug) {
94
- localConsole.log(`exit code ${exitCode}`);
95
- localConsole.log(`STDOUT: ${execResult.stdout}`);
96
- localConsole.log(`STDERR: ${execResult.stderr}`);
80
+ logger.log(`${log.dim}$ ${command} ${args.join(' ')} ${log.reset}`);
81
+
82
+ const cp = spawn(command, args, {env});
83
+ cp.stdout.on('data', data => logger.log(`[STDOUT] ${data.toString().trim()}`));
84
+ cp.stderr.on('data', data => logger.log(`[STDERR] ${data.toString().trim()}`));
85
+ /** @type {Promise<number|null>} */
86
+ const cpPromise = new Promise((resolve, reject) => {
87
+ cp.addListener('exit', resolve);
88
+ cp.addListener('error', reject);
89
+ });
90
+ const exitCode = await cpPromise;
91
+ if (exitCode) {
92
+ logger.log(`exit code ${exitCode}`);
97
93
  }
98
94
 
99
95
  try {
100
96
  await fs.access(outputPath);
101
97
  } catch (e) {
102
- throw new ChildProcessError(`Lighthouse run failed to produce a report and exited with ${exitCode}.`, // eslint-disable-line max-len
103
- localConsole.getLog());
98
+ throw new ChildProcessError(`Lighthouse run failed to produce a report.`, logger.getLog());
104
99
  }
105
100
 
106
101
  /** @type {LH.Result} */
@@ -109,21 +104,20 @@ async function internalRun(url, tmpPath, config, options) {
109
104
 
110
105
  // Output has been established as existing, so can log for debug.
111
106
  if (isDebug) {
112
- localConsole.log(`LHR output available at: ${outputPath}`);
113
- localConsole.log(`Artifacts avaiable in: ${artifactsDirectory}`);
107
+ logger.log(`LHR output available at: ${outputPath}`);
108
+ logger.log(`Artifacts avaiable in: ${artifactsDirectory}`);
114
109
  }
115
110
 
116
111
  // There should either be both an error exitCode and a lhr.runtimeError or neither.
117
112
  if (Boolean(exitCode) !== Boolean(lhr.runtimeError)) {
118
113
  const runtimeErrorCode = lhr.runtimeError?.code;
119
114
  throw new ChildProcessError(`Lighthouse did not exit with an error correctly, exiting with ${exitCode} but with runtimeError '${runtimeErrorCode}'`, // eslint-disable-line max-len
120
- localConsole.getLog());
115
+ logger.getLog());
121
116
  }
122
117
 
123
118
  return {
124
119
  lhr,
125
120
  artifacts,
126
- log: localConsole.getLog(),
127
121
  };
128
122
  }
129
123
 
@@ -5,13 +5,13 @@
5
5
  * CHROME_PATH determines which Chrome is used–otherwise the default is puppeteer's chrome binary.
6
6
  * @param {string} url
7
7
  * @param {LH.Config=} config
8
+ * @param {import('../lib/local-console.js').LocalConsole=} logger
8
9
  * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
9
- * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
10
+ * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts}>}
10
11
  */
11
- export function runLighthouse(url: string, config?: LH.Config | undefined, testRunnerOptions?: Smokehouse.SmokehouseOptions["testRunnerOptions"] | undefined): Promise<{
12
+ export function runLighthouse(url: string, config?: LH.Config | undefined, logger?: import("../lib/local-console.js").LocalConsole | undefined, testRunnerOptions?: Smokehouse.SmokehouseOptions["testRunnerOptions"] | undefined): Promise<{
12
13
  lhr: LH.Result;
13
14
  artifacts: LH.Artifacts;
14
- log: string;
15
15
  }>;
16
16
  /**
17
17
  * Download/pull latest DevTools, build Lighthouse for DevTools, roll to DevTools, and build DevTools.
@@ -40,21 +40,24 @@ async function setup() {
40
40
  * CHROME_PATH determines which Chrome is used–otherwise the default is puppeteer's chrome binary.
41
41
  * @param {string} url
42
42
  * @param {LH.Config=} config
43
+ * @param {import('../lib/local-console.js').LocalConsole=} logger
43
44
  * @param {Smokehouse.SmokehouseOptions['testRunnerOptions']=} testRunnerOptions
44
- * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
45
+ * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts}>}
45
46
  */
46
- async function runLighthouse(url, config, testRunnerOptions) {
47
+ async function runLighthouse(url, config, logger, testRunnerOptions) {
47
48
  const chromeFlags = [
48
49
  testRunnerOptions?.headless ? '--headless=new' : '',
49
50
  `--custom-devtools-frontend=file://${devtoolsDir}/out/LighthouseIntegration/gen/front_end`,
50
51
  ];
52
+ // TODO: `testUrlFromDevtools` should accept a logger, so we get some output even for time outs.
51
53
  const {lhr, artifacts, logs} = await testUrlFromDevtools(url, {
52
54
  config,
53
55
  chromeFlags,
54
56
  });
55
-
56
- const log = logs.join('') + '\n';
57
- return {lhr, artifacts, log};
57
+ if (logger) {
58
+ logger.log(logs.join('') + '\n');
59
+ }
60
+ return {lhr, artifacts};
58
61
  }
59
62
 
60
63
  export {
@@ -161,6 +161,8 @@ async function runSmokeTest(smokeTestDefn, testOptions) {
161
161
  bufferedConsole.log(` Retrying run (${i} out of ${retries} retries)…`);
162
162
  }
163
163
 
164
+ const logger = new LocalConsole();
165
+
164
166
  // Run Lighthouse.
165
167
  try {
166
168
  // Each individual runner has internal timeouts, but we've had bugs where
@@ -170,12 +172,13 @@ async function runSmokeTest(smokeTestDefn, testOptions) {
170
172
  reject(new Error('Timed out waiting for provided lighthouseRunner')), 1000 * 120);
171
173
  });
172
174
  const timedResult = await Promise.race([
173
- lighthouseRunner(requestedUrl, config, testRunnerOptions),
175
+ lighthouseRunner(requestedUrl, config, logger, testRunnerOptions),
174
176
  timeoutPromise,
175
177
  ]);
176
178
  result = {
177
179
  ...timedResult,
178
180
  networkRequests: takeNetworkRequestUrls ? takeNetworkRequestUrls() : undefined,
181
+ log: logger.getLog(),
179
182
  };
180
183
 
181
184
  if (!result.lhr?.audits || !result.artifacts) {
@@ -188,6 +191,8 @@ async function runSmokeTest(smokeTestDefn, testOptions) {
188
191
  if (takeNetworkRequestUrls) takeNetworkRequestUrls();
189
192
 
190
193
  logChildProcessError(bufferedConsole, e);
194
+ bufferedConsole.log('Timed out. log from lighthouseRunner:');
195
+ bufferedConsole.log(logger.getLog());
191
196
  continue; // Retry, if possible.
192
197
  }
193
198
 
@@ -20,7 +20,7 @@ const UIStrings = {
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Access keys let users quickly focus a part of the page. For proper ' +
22
22
  'navigation, each access key must be unique. ' +
23
- '[Learn more about access keys](https://dequeuniversity.com/rules/axe/4.9/accesskeys).',
23
+ '[Learn more about access keys](https://dequeuniversity.com/rules/axe/4.10/accesskeys).',
24
24
  };
25
25
 
26
26
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -20,7 +20,7 @@ const UIStrings = {
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Each ARIA `role` supports a specific subset of `aria-*` attributes. ' +
22
22
  'Mismatching these invalidates the `aria-*` attributes. [Learn ' +
23
- 'how to match ARIA attributes to their roles](https://dequeuniversity.com/rules/axe/4.9/aria-allowed-attr).',
23
+ 'how to match ARIA attributes to their roles](https://dequeuniversity.com/rules/axe/4.10/aria-allowed-attr).',
24
24
  };
25
25
 
26
26
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -20,7 +20,7 @@ const UIStrings = {
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Many HTML elements can only be assigned certain ARIA roles. Using ARIA ' +
22
22
  'roles where they are not allowed can interfere with the accessibility of the web page. ' +
23
- '[Learn more about ARIA roles](https://dequeuniversity.com/rules/axe/4.9/aria-allowed-role).',
23
+ '[Learn more about ARIA roles](https://dequeuniversity.com/rules/axe/4.10/aria-allowed-role).',
24
24
  };
25
25
 
26
26
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -18,7 +18,7 @@ const UIStrings = {
18
18
  /** Title of an accessibility audit that evaluates if important HTML elements do not have accessible names. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
19
  failureTitle: '`button`, `link`, and `menuitem` elements do not have accessible names.',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should have accessible names for HTML elements. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
- description: 'When an element doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to make command elements more accessible](https://dequeuniversity.com/rules/axe/4.9/aria-command-name).',
21
+ description: 'When an element doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to make command elements more accessible](https://dequeuniversity.com/rules/axe/4.10/aria-command-name).',
22
22
  };
23
23
 
24
24
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -19,7 +19,7 @@ const UIStrings = {
19
19
  failureTitle: 'ARIA attributes are not used as specified for the element\'s role',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Some ARIA attributes are only allowed on an element under certain conditions. ' +
22
- '[Learn more about conditional ARIA attributes](https://dequeuniversity.com/rules/axe/4.9/aria-conditional-attr).',
22
+ '[Learn more about conditional ARIA attributes](https://dequeuniversity.com/rules/axe/4.10/aria-conditional-attr).',
23
23
  };
24
24
 
25
25
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -19,7 +19,7 @@ const UIStrings = {
19
19
  failureTitle: 'Deprecated ARIA roles were used',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Deprecated ARIA roles may not be processed correctly by assistive technology. ' +
22
- '[Learn more about deprecated ARIA roles](https://dequeuniversity.com/rules/axe/4.9/aria-deprecated-role).',
22
+ '[Learn more about deprecated ARIA roles](https://dequeuniversity.com/rules/axe/4.10/aria-deprecated-role).',
23
23
  };
24
24
 
25
25
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -21,7 +21,7 @@ const UIStrings = {
21
21
  /** Description of a Lighthouse audit that tells the user *why* they should have accessible names for ARIA dialog elements. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
22
22
  description: 'ARIA dialog elements without accessible names may prevent screen readers users ' +
23
23
  'from discerning the purpose of these elements. ' +
24
- '[Learn how to make ARIA dialog elements more accessible](https://dequeuniversity.com/rules/axe/4.9/aria-dialog-name).',
24
+ '[Learn how to make ARIA dialog elements more accessible](https://dequeuniversity.com/rules/axe/4.10/aria-dialog-name).',
25
25
  };
26
26
 
27
27
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -18,7 +18,7 @@ const UIStrings = {
18
18
  /** Title of an accesibility audit that checks if the html <body> element does not have an aria-hidden attribute set on it. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
19
  failureTitle: '`[aria-hidden="true"]` is present on the document `<body>`',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
- description: 'Assistive technologies, like screen readers, work inconsistently when `aria-hidden="true"` is set on the document `<body>`. [Learn how `aria-hidden` affects the document body](https://dequeuniversity.com/rules/axe/4.9/aria-hidden-body).',
21
+ description: 'Assistive technologies, like screen readers, work inconsistently when `aria-hidden="true"` is set on the document `<body>`. [Learn how `aria-hidden` affects the document body](https://dequeuniversity.com/rules/axe/4.10/aria-hidden-body).',
22
22
  };
23
23
 
24
24
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -18,7 +18,7 @@ const UIStrings = {
18
18
  /** Title of an accesibility audit that checks if all elements that have an aria-hidden attribute do not contain focusable descendent elements. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
19
  failureTitle: '`[aria-hidden="true"]` elements contain focusable descendents',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
- description: 'Focusable descendents within an `[aria-hidden="true"]` element prevent those interactive elements from being available to users of assistive technologies like screen readers. [Learn how `aria-hidden` affects focusable elements](https://dequeuniversity.com/rules/axe/4.9/aria-hidden-focus).',
21
+ description: 'Focusable descendents within an `[aria-hidden="true"]` element prevent those interactive elements from being available to users of assistive technologies like screen readers. [Learn how `aria-hidden` affects focusable elements](https://dequeuniversity.com/rules/axe/4.10/aria-hidden-focus).',
22
22
  };
23
23
 
24
24
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -18,7 +18,7 @@ const UIStrings = {
18
18
  /** Title of an accesibility audit that checks that all ARIA input fields have an accessible name. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
19
  failureTitle: 'ARIA input fields do not have accessible names',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
- description: 'When an input field doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about input field labels](https://dequeuniversity.com/rules/axe/4.9/aria-input-field-name).',
21
+ description: 'When an input field doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about input field labels](https://dequeuniversity.com/rules/axe/4.10/aria-input-field-name).',
22
22
  };
23
23
 
24
24
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -18,7 +18,7 @@ const UIStrings = {
18
18
  /** Title of an accessibility audit that evaluates if meter HTML elements do not have accessible names. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
19
  failureTitle: 'ARIA `meter` elements do not have accessible names.',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should have accessible names for HTML 'meter' elements. This is displayed after a user expands the section to see more. No character length limits. 'Learn how...' becomes link text to additional documentation. */
21
- description: 'When a meter element doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to name `meter` elements](https://dequeuniversity.com/rules/axe/4.9/aria-meter-name).',
21
+ description: 'When a meter element doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to name `meter` elements](https://dequeuniversity.com/rules/axe/4.10/aria-meter-name).',
22
22
  };
23
23
 
24
24
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -18,7 +18,7 @@ const UIStrings = {
18
18
  /** Title of an accessibility audit that evaluates if progressbar HTML elements do not have accessible names. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
19
  failureTitle: 'ARIA `progressbar` elements do not have accessible names.',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
- description: 'When a `progressbar` element doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to label `progressbar` elements](https://dequeuniversity.com/rules/axe/4.9/aria-progressbar-name).',
21
+ description: 'When a `progressbar` element doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to label `progressbar` elements](https://dequeuniversity.com/rules/axe/4.10/aria-progressbar-name).',
22
22
  };
23
23
 
24
24
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -20,7 +20,7 @@ const UIStrings = {
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Using ARIA attributes in roles where they are prohibited can mean that important ' +
22
22
  'information is not communicated to users of assistive technologies. ' +
23
- '[Learn more about prohibited ARIA roles](https://dequeuniversity.com/rules/axe/4.9/aria-prohibited-attr).',
23
+ '[Learn more about prohibited ARIA roles](https://dequeuniversity.com/rules/axe/4.10/aria-prohibited-attr).',
24
24
  };
25
25
 
26
26
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -19,7 +19,7 @@ const UIStrings = {
19
19
  failureTitle: '`[role]`s do not have all required `[aria-*]` attributes',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Some ARIA roles have required attributes that describe the state ' +
22
- 'of the element to screen readers. [Learn more about roles and required attributes](https://dequeuniversity.com/rules/axe/4.9/aria-required-attr).',
22
+ 'of the element to screen readers. [Learn more about roles and required attributes](https://dequeuniversity.com/rules/axe/4.10/aria-required-attr).',
23
23
  };
24
24
 
25
25
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -23,7 +23,7 @@ const UIStrings = {
23
23
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
24
24
  description: 'Some ARIA parent roles must contain specific child roles to perform ' +
25
25
  'their intended accessibility functions. ' +
26
- '[Learn more about roles and required children elements](https://dequeuniversity.com/rules/axe/4.9/aria-required-children).',
26
+ '[Learn more about roles and required children elements](https://dequeuniversity.com/rules/axe/4.10/aria-required-children).',
27
27
  };
28
28
 
29
29
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -21,7 +21,7 @@ const UIStrings = {
21
21
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
22
22
  description: 'Some ARIA child roles must be contained by specific parent roles to ' +
23
23
  'properly perform their intended accessibility functions. ' +
24
- '[Learn more about ARIA roles and required parent element](https://dequeuniversity.com/rules/axe/4.9/aria-required-parent).',
24
+ '[Learn more about ARIA roles and required parent element](https://dequeuniversity.com/rules/axe/4.10/aria-required-parent).',
25
25
  };
26
26
 
27
27
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -20,7 +20,7 @@ const UIStrings = {
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'ARIA roles must have valid values in order to perform their ' +
22
22
  'intended accessibility functions. ' +
23
- '[Learn more about valid ARIA roles](https://dequeuniversity.com/rules/axe/4.9/aria-roles).',
23
+ '[Learn more about valid ARIA roles](https://dequeuniversity.com/rules/axe/4.10/aria-roles).',
24
24
  };
25
25
 
26
26
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -20,7 +20,7 @@ const UIStrings = {
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Adding `role=text` around a text node split by markup enables VoiceOver to treat ' +
22
22
  'it as one phrase, but the element\'s focusable descendents will not be announced. ' +
23
- '[Learn more about the `role=text` attribute](https://dequeuniversity.com/rules/axe/4.9/aria-text).',
23
+ '[Learn more about the `role=text` attribute](https://dequeuniversity.com/rules/axe/4.10/aria-text).',
24
24
  };
25
25
 
26
26
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -18,7 +18,7 @@ const UIStrings = {
18
18
  /** Title of an accesibility audit that checks that all ARIA toggle fields have an accessible name. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
19
  failureTitle: 'ARIA toggle fields do not have accessible names',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
- description: 'When a toggle field doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about toggle fields](https://dequeuniversity.com/rules/axe/4.9/aria-toggle-field-name).',
21
+ description: 'When a toggle field doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about toggle fields](https://dequeuniversity.com/rules/axe/4.10/aria-toggle-field-name).',
22
22
  };
23
23
 
24
24
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -18,7 +18,7 @@ const UIStrings = {
18
18
  /** Title of an accessibility audit that evaluates if tooltip HTML elements do not have accessible names. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
19
  failureTitle: 'ARIA `tooltip` elements do not have accessible names.',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should have accessible names for HTML 'tooltip' elements. This is displayed after a user expands the section to see more. No character length limits. 'Learn how...' becomes link text to additional documentation. */
21
- description: 'When a tooltip element doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to name `tooltip` elements](https://dequeuniversity.com/rules/axe/4.9/aria-tooltip-name).',
21
+ description: 'When a tooltip element doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to name `tooltip` elements](https://dequeuniversity.com/rules/axe/4.10/aria-tooltip-name).',
22
22
  };
23
23
 
24
24
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -18,7 +18,7 @@ const UIStrings = {
18
18
  /** Title of an accessibility audit that evaluates if treeitem HTML elements do not have accessible names. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */
19
19
  failureTitle: 'ARIA `treeitem` elements do not have accessible names.',
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should have accessible names for HTML elements. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
- description: 'When a `treeitem` element doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about labeling `treeitem` elements](https://dequeuniversity.com/rules/axe/4.9/aria-treeitem-name).',
21
+ description: 'When a `treeitem` element doesn\'t have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about labeling `treeitem` elements](https://dequeuniversity.com/rules/axe/4.10/aria-treeitem-name).',
22
22
  };
23
23
 
24
24
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -20,7 +20,7 @@ const UIStrings = {
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Assistive technologies, like screen readers, can\'t interpret ARIA ' +
22
22
  'attributes with invalid values. [Learn ' +
23
- 'more about valid values for ARIA attributes](https://dequeuniversity.com/rules/axe/4.9/aria-valid-attr-value).',
23
+ 'more about valid values for ARIA attributes](https://dequeuniversity.com/rules/axe/4.10/aria-valid-attr-value).',
24
24
  };
25
25
 
26
26
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -20,7 +20,7 @@ const UIStrings = {
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Assistive technologies, like screen readers, can\'t interpret ARIA ' +
22
22
  'attributes with invalid names. [Learn ' +
23
- 'more about valid ARIA attributes](https://dequeuniversity.com/rules/axe/4.9/aria-valid-attr).',
23
+ 'more about valid ARIA attributes](https://dequeuniversity.com/rules/axe/4.10/aria-valid-attr).',
24
24
  };
25
25
 
26
26
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -20,7 +20,7 @@ const UIStrings = {
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'When a button doesn\'t have an accessible name, screen readers announce it ' +
22
22
  'as "button", making it unusable for users who rely on screen readers. ' +
23
- '[Learn how to make buttons more accessible](https://dequeuniversity.com/rules/axe/4.9/button-name).',
23
+ '[Learn how to make buttons more accessible](https://dequeuniversity.com/rules/axe/4.10/button-name).',
24
24
  };
25
25
 
26
26
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -21,7 +21,7 @@ const UIStrings = {
21
21
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
22
22
  description: 'Adding ways to bypass repetitive content lets keyboard users navigate the ' +
23
23
  'page more efficiently. ' +
24
- '[Learn more about bypass blocks](https://dequeuniversity.com/rules/axe/4.9/bypass).',
24
+ '[Learn more about bypass blocks](https://dequeuniversity.com/rules/axe/4.10/bypass).',
25
25
  };
26
26
 
27
27
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -21,7 +21,7 @@ const UIStrings = {
21
21
  'sufficient contrast ratio.',
22
22
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
23
23
  description: 'Low-contrast text is difficult or impossible for many users to read. ' +
24
- '[Learn how to provide sufficient color contrast](https://dequeuniversity.com/rules/axe/4.9/color-contrast).',
24
+ '[Learn how to provide sufficient color contrast](https://dequeuniversity.com/rules/axe/4.10/color-contrast).',
25
25
  };
26
26
 
27
27
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -22,7 +22,7 @@ const UIStrings = {
22
22
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
23
23
  description: 'When definition lists are not properly marked up, screen readers may produce ' +
24
24
  'confusing or inaccurate output. ' +
25
- '[Learn how to structure definition lists correctly](https://dequeuniversity.com/rules/axe/4.9/definition-list).',
25
+ '[Learn how to structure definition lists correctly](https://dequeuniversity.com/rules/axe/4.10/definition-list).',
26
26
  };
27
27
 
28
28
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
@@ -20,7 +20,7 @@ const UIStrings = {
20
20
  /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
21
21
  description: 'Definition list items (`<dt>` and `<dd>`) must be wrapped in a ' +
22
22
  'parent `<dl>` element to ensure that screen readers can properly announce them. ' +
23
- '[Learn how to structure definition lists correctly](https://dequeuniversity.com/rules/axe/4.9/dlitem).',
23
+ '[Learn how to structure definition lists correctly](https://dequeuniversity.com/rules/axe/4.10/dlitem).',
24
24
  };
25
25
 
26
26
  const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);