aria-ease 6.6.0 → 6.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +75 -15
  2. package/bin/{chunk-LKN5PRYD.js → chunk-2TOYEY5L.js} +87 -35
  3. package/bin/chunk-VPBHLMAS.js +127 -0
  4. package/bin/cli.cjs +380 -231
  5. package/bin/cli.js +8 -123
  6. package/bin/configLoader-XRF6VM4J.js +7 -0
  7. package/{dist/contractTestRunnerPlaywright-PC6JOYYV.js → bin/contractTestRunnerPlaywright-UAOFNS7Z.js} +98 -59
  8. package/bin/{test-LP723IXM.js → test-WRIJHN6H.js} +65 -24
  9. package/dist/{chunk-LKN5PRYD.js → chunk-2TOYEY5L.js} +87 -35
  10. package/dist/configLoader-IT4PWCJB.js +128 -0
  11. package/{bin/contractTestRunnerPlaywright-PC6JOYYV.js → dist/contractTestRunnerPlaywright-UAOFNS7Z.js} +98 -59
  12. package/dist/index.cjs +404 -125
  13. package/dist/index.d.cts +6 -1
  14. package/dist/index.d.ts +6 -1
  15. package/dist/index.js +83 -29
  16. package/dist/src/menu/index.cjs +18 -5
  17. package/dist/src/menu/index.js +18 -5
  18. package/dist/src/utils/test/aria-contracts/accordion/accordion.contract.json +8 -8
  19. package/dist/src/utils/test/aria-contracts/combobox/combobox.listbox.contract.json +4 -4
  20. package/dist/src/utils/test/aria-contracts/menu/menu.contract.json +44 -19
  21. package/dist/src/utils/test/aria-contracts/tabs/tabs.contract.json +3 -3
  22. package/dist/src/utils/test/{chunk-LKN5PRYD.js → chunk-2TOYEY5L.js} +85 -36
  23. package/dist/src/utils/test/configLoader-LD4RV2WQ.js +126 -0
  24. package/dist/src/utils/test/{contractTestRunnerPlaywright-RGKMGXND.js → contractTestRunnerPlaywright-IRJOAEMT.js} +94 -58
  25. package/dist/src/utils/test/index.cjs +380 -119
  26. package/dist/src/utils/test/index.d.cts +7 -1
  27. package/dist/src/utils/test/index.d.ts +7 -1
  28. package/dist/src/utils/test/index.js +61 -23
  29. package/package.json +1 -1
@@ -7,8 +7,11 @@ interface ContractTestResult {
7
7
  passes: string[];
8
8
  failures: string[];
9
9
  skipped: string[];
10
+ warnings?: string[];
10
11
  }
11
12
 
13
+ type StrictnessMode = 'minimal' | 'balanced' | 'strict' | 'paranoid';
14
+
12
15
  /**
13
16
  * Runs static and interactions accessibility test on UI components.
14
17
  * @param {string} componentName The name of the component contract to test against
@@ -16,7 +19,10 @@ interface ContractTestResult {
16
19
  * @param {string} url Optional URL to run full Playwright E2E tests. If omitted, uses isolated component testing with page.setContent()
17
20
  */
18
21
 
19
- declare function testUiComponent(componentName: string, component: HTMLElement | null, url: string | null): Promise<JestAxeResult>;
22
+ type TestAuditOptions = {
23
+ strictness?: StrictnessMode;
24
+ };
25
+ declare function testUiComponent(componentName: string, component: HTMLElement | null, url: string | null, options?: TestAuditOptions): Promise<JestAxeResult>;
20
26
  declare let runTest: () => Promise<ContractTestResult>;
21
27
  /**
22
28
  * Cleanup function to close the shared Playwright browser
@@ -7,8 +7,11 @@ interface ContractTestResult {
7
7
  passes: string[];
8
8
  failures: string[];
9
9
  skipped: string[];
10
+ warnings?: string[];
10
11
  }
11
12
 
13
+ type StrictnessMode = 'minimal' | 'balanced' | 'strict' | 'paranoid';
14
+
12
15
  /**
13
16
  * Runs static and interactions accessibility test on UI components.
14
17
  * @param {string} componentName The name of the component contract to test against
@@ -16,7 +19,10 @@ interface ContractTestResult {
16
19
  * @param {string} url Optional URL to run full Playwright E2E tests. If omitted, uses isolated component testing with page.setContent()
17
20
  */
18
21
 
19
- declare function testUiComponent(componentName: string, component: HTMLElement | null, url: string | null): Promise<JestAxeResult>;
22
+ type TestAuditOptions = {
23
+ strictness?: StrictnessMode;
24
+ };
25
+ declare function testUiComponent(componentName: string, component: HTMLElement | null, url: string | null, options?: TestAuditOptions): Promise<JestAxeResult>;
20
26
  declare let runTest: () => Promise<ContractTestResult>;
21
27
  /**
22
28
  * Cleanup function to close the shared Playwright browser
@@ -1,9 +1,10 @@
1
- import { closeSharedBrowser, ContractReporter, contract_default } from './chunk-LKN5PRYD.js';
1
+ import { normalizeStrictness, closeSharedBrowser, ContractReporter, contract_default, normalizeLevel, resolveEnforcement } from './chunk-2TOYEY5L.js';
2
2
  import { axe } from 'jest-axe';
3
3
  import fs from 'fs/promises';
4
4
 
5
- async function runContractTests(componentName, component) {
5
+ async function runContractTests(componentName, component, strictness) {
6
6
  const reporter = new ContractReporter(false);
7
+ const strictnessMode = normalizeStrictness(strictness);
7
8
  const contractTyped = contract_default;
8
9
  const contractPath = contractTyped[componentName]?.path;
9
10
  if (!contractPath) {
@@ -17,19 +18,42 @@ async function runContractTests(componentName, component) {
17
18
  const failures = [];
18
19
  const passes = [];
19
20
  const skipped = [];
20
- const failuresBeforeStatic = failures.length;
21
+ const warnings = [];
22
+ const classifyFailure = (message, levelRaw) => {
23
+ const level = normalizeLevel(levelRaw);
24
+ const enforcement = resolveEnforcement(level, strictnessMode);
25
+ if (enforcement === "error") {
26
+ failures.push(message);
27
+ return { status: "fail", level, detail: message };
28
+ }
29
+ if (enforcement === "warning") {
30
+ warnings.push(message);
31
+ return { status: "warn", level, detail: message };
32
+ }
33
+ const ignoredMessage = `${message} (ignored by strictness=${strictnessMode}, level=${level})`;
34
+ skipped.push(ignoredMessage);
35
+ return { status: "skip", level, detail: ignoredMessage };
36
+ };
37
+ let staticPassed = 0;
38
+ let staticFailed = 0;
39
+ let staticWarnings = 0;
21
40
  for (const test of componentContract.static[0].assertions) {
22
41
  if (test.target !== "relative") {
42
+ const staticLevel = normalizeLevel(test.level);
23
43
  const selector = componentContract.selectors[test.target];
24
44
  if (!selector) {
25
- failures.push(`Selector for target ${test.target} not found.`);
26
- reporter.reportStaticTest(`${test.target} has required ARIA attributes`, false, `Selector for target ${test.target} not found.`);
45
+ const outcome = classifyFailure(`Selector for target ${test.target} not found.`, test.level);
46
+ if (outcome.status === "fail") staticFailed += 1;
47
+ if (outcome.status === "warn") staticWarnings += 1;
48
+ reporter.reportStaticTest(`${test.target} has required ARIA attributes`, outcome.status, outcome.detail, outcome.level);
27
49
  continue;
28
50
  }
29
51
  const target = component.querySelector(selector);
30
52
  if (!target) {
31
- failures.push(`Target ${test.target} not found.`);
32
- reporter.reportStaticTest(`${test.target} has required ARIA attributes`, false, `Target ${test.target} not found.`);
53
+ const outcome = classifyFailure(`Target ${test.target} not found.`, test.level);
54
+ if (outcome.status === "fail") staticFailed += 1;
55
+ if (outcome.status === "warn") staticWarnings += 1;
56
+ reporter.reportStaticTest(`${test.target} has required ARIA attributes`, outcome.status, outcome.detail, outcome.level);
33
57
  continue;
34
58
  }
35
59
  const attributeValue = target.getAttribute(test.attribute);
@@ -37,35 +61,38 @@ async function runContractTests(componentName, component) {
37
61
  const attributes = test.attribute.split(" | ");
38
62
  const hasAnyAttribute = attributes.some((attr) => target.hasAttribute(attr));
39
63
  if (!hasAnyAttribute) {
40
- failures.push(test.failureMessage + ` None of the attributes "${test.attribute}" are present.`);
41
- reporter.reportStaticTest(`${test.target} has ${test.attribute}`, false, test.failureMessage);
64
+ const outcome = classifyFailure(test.failureMessage + ` None of the attributes "${test.attribute}" are present.`, test.level);
65
+ if (outcome.status === "fail") staticFailed += 1;
66
+ if (outcome.status === "warn") staticWarnings += 1;
67
+ reporter.reportStaticTest(`${test.target} has ${test.attribute}`, outcome.status, outcome.detail, outcome.level);
42
68
  } else {
43
69
  passes.push(`At least one of the attributes "${test.attribute}" exists on the element.`);
44
- reporter.reportStaticTest(`${test.target} has ${test.attribute}`, true);
70
+ staticPassed += 1;
71
+ reporter.reportStaticTest(`${test.target} has ${test.attribute}`, "pass", void 0, staticLevel);
45
72
  }
46
73
  } else if (!attributeValue || !test.expectedValue.split(" | ").includes(attributeValue)) {
47
- failures.push(test.failureMessage + ` Attribute value does not match expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);
48
- reporter.reportStaticTest(`${test.target} has ${test.attribute}="${test.expectedValue}"`, false, test.failureMessage);
74
+ const outcome = classifyFailure(test.failureMessage + ` Attribute value does not match expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`, test.level);
75
+ if (outcome.status === "fail") staticFailed += 1;
76
+ if (outcome.status === "warn") staticWarnings += 1;
77
+ reporter.reportStaticTest(`${test.target} has ${test.attribute}="${test.expectedValue}"`, outcome.status, outcome.detail, outcome.level);
49
78
  } else {
50
79
  passes.push(`Attribute value matches expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);
51
- reporter.reportStaticTest(`${test.target} has ${test.attribute}="${attributeValue}"`, true);
80
+ staticPassed += 1;
81
+ reporter.reportStaticTest(`${test.target} has ${test.attribute}="${attributeValue}"`, "pass", void 0, staticLevel);
52
82
  }
53
83
  }
54
84
  }
55
85
  for (const dynamicTest of componentContract.dynamic) {
56
86
  skipped.push(dynamicTest.description);
57
- reporter.reportTest(dynamicTest, "skip");
87
+ reporter.reportTest({ description: dynamicTest.description, level: dynamicTest.level }, "skip");
58
88
  }
59
- const staticTotal = componentContract.static[0].assertions.length;
60
- const staticFailed = failures.length - failuresBeforeStatic;
61
- const staticPassed = Math.max(0, staticTotal - staticFailed);
62
- reporter.reportStatic(staticPassed, staticFailed);
89
+ reporter.reportStatic(staticPassed, staticFailed, staticWarnings);
63
90
  reporter.summary(failures);
64
- return { passes, failures, skipped };
91
+ return { passes, failures, skipped, warnings };
65
92
  }
66
93
 
67
94
  // src/utils/test/src/test.ts
68
- async function testUiComponent(componentName, component, url) {
95
+ async function testUiComponent(componentName, component, url, options = {}) {
69
96
  if (!componentName || typeof componentName !== "string") {
70
97
  throw new Error("\u274C testUiComponent requires a valid componentName (string)");
71
98
  }
@@ -102,14 +129,25 @@ Error: ${error instanceof Error ? error.message : String(error)}`
102
129
  }
103
130
  return null;
104
131
  }
132
+ let strictness = normalizeStrictness(options.strictness);
133
+ if (options.strictness === void 0 && typeof window === "undefined") {
134
+ try {
135
+ const { loadConfig } = await import('./configLoader-LD4RV2WQ.js');
136
+ const { config } = await loadConfig(process.cwd());
137
+ const componentStrictness = config.test?.components?.find((comp) => comp?.name === componentName)?.strictness;
138
+ strictness = normalizeStrictness(componentStrictness ?? config.test?.strictness);
139
+ } catch {
140
+ strictness = "balanced";
141
+ }
142
+ }
105
143
  let contract;
106
144
  try {
107
145
  if (url) {
108
146
  const devServerUrl = await checkDevServer(url);
109
147
  if (devServerUrl) {
110
148
  console.log(`\u{1F3AD} Running Playwright tests on ${devServerUrl}`);
111
- const { runContractTestsPlaywright } = await import('./contractTestRunnerPlaywright-RGKMGXND.js');
112
- contract = await runContractTestsPlaywright(componentName, devServerUrl);
149
+ const { runContractTestsPlaywright } = await import('./contractTestRunnerPlaywright-IRJOAEMT.js');
150
+ contract = await runContractTestsPlaywright(componentName, devServerUrl, strictness);
113
151
  } else {
114
152
  throw new Error(
115
153
  `\u274C Dev server not running at ${url}
@@ -118,7 +156,7 @@ Please start your dev server and try again.`
118
156
  }
119
157
  } else if (component) {
120
158
  console.log(`\u{1F3AD} Running component contract tests in JSDOM mode`);
121
- contract = await runContractTests(componentName, component);
159
+ contract = await runContractTests(componentName, component, strictness);
122
160
  } else {
123
161
  throw new Error("\u274C Either component or URL must be provided");
124
162
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aria-ease",
3
- "version": "6.6.0",
3
+ "version": "6.7.0",
4
4
  "description": "Accessibility infrastructure for the entire frontend engineering lifecycle. Build accessible patterns, run automated audits, verify component interactions, and gate deployments — all in one system.",
5
5
  "main": "dist/index.cjs",
6
6
  "type": "module",