aria-ease 6.4.10 → 6.5.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.
- package/bin/{chunk-GFKAJHCS.js → chunk-AUJAN4RK.js} +34 -18
- package/bin/cli.cjs +67 -35
- package/bin/cli.js +1 -1
- package/{dist/contractTestRunnerPlaywright-7BCEDPZF.js → bin/contractTestRunnerPlaywright-7F756CFB.js} +26 -12
- package/bin/{test-JGKWOL6J.js → test-C3CMRHSI.js} +7 -5
- package/dist/{chunk-GFKAJHCS.js → chunk-AUJAN4RK.js} +34 -18
- package/{bin/contractTestRunnerPlaywright-7BCEDPZF.js → dist/contractTestRunnerPlaywright-7F756CFB.js} +26 -12
- package/dist/index.cjs +148 -106
- package/dist/index.js +89 -77
- package/dist/src/block/index.cjs +1 -6
- package/dist/src/block/index.js +72 -1
- package/dist/src/menu/index.cjs +79 -147
- package/dist/src/menu/index.js +79 -23
- package/dist/src/utils/test/{contracts/AccordionContract.json → aria-contracts/accordion/accordion.contract.json} +21 -8
- package/dist/src/utils/test/{contracts/ComboboxContract.json → aria-contracts/combobox/combobox.listbox.contract.json} +18 -18
- package/dist/src/utils/test/{contracts/MenuContract.json → aria-contracts/menu/menu.contract.json} +43 -2
- package/dist/src/utils/test/{contracts/TabsContract.json → aria-contracts/tabs/tabs.contract.json} +21 -8
- package/dist/src/utils/test/{chunk-GFKAJHCS.js → chunk-AUJAN4RK.js} +33 -17
- package/dist/src/utils/test/{contractTestRunnerPlaywright-O7FF3X67.js → contractTestRunnerPlaywright-HL73FADJ.js} +25 -11
- package/dist/src/utils/test/index.cjs +65 -33
- package/dist/src/utils/test/index.js +6 -4
- package/package.json +2 -2
- package/dist/src/chunk-ZJXZZDUR.js +0 -127
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
// src/utils/test/contract/contract.json
|
|
2
2
|
var contract_default = {
|
|
3
3
|
menu: {
|
|
4
|
-
path: "./contracts/
|
|
4
|
+
path: "./aria-contracts/menu/menu.contract.json",
|
|
5
5
|
component: "menu"
|
|
6
6
|
},
|
|
7
|
-
combobox: {
|
|
8
|
-
path: "./contracts/
|
|
9
|
-
component: "combobox"
|
|
7
|
+
"combobox.listbox": {
|
|
8
|
+
path: "./aria-contracts/combobox/combobox.listbox.contract.json",
|
|
9
|
+
component: "combobox.listbox"
|
|
10
10
|
},
|
|
11
11
|
accordion: {
|
|
12
|
-
path: "./contracts/
|
|
12
|
+
path: "./aria-contracts/accordion/accordion.contract.json",
|
|
13
13
|
component: "accordion"
|
|
14
14
|
},
|
|
15
15
|
tabs: {
|
|
16
|
-
path: "./contracts/
|
|
16
|
+
path: "./aria-contracts/tabs/tabs.contract.json",
|
|
17
17
|
component: "tabs"
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
// src/utils/test/
|
|
21
|
+
// src/utils/test/src/ContractReporter.ts
|
|
22
22
|
var ContractReporter = class {
|
|
23
23
|
startTime = 0;
|
|
24
24
|
componentName = "";
|
|
@@ -30,6 +30,8 @@ var ContractReporter = class {
|
|
|
30
30
|
optionalSuggestions = 0;
|
|
31
31
|
isPlaywright = false;
|
|
32
32
|
apgUrl = "https://www.w3.org/WAI/ARIA/apg/";
|
|
33
|
+
hasPrintedStaticSection = false;
|
|
34
|
+
hasPrintedDynamicSection = false;
|
|
33
35
|
constructor(isPlaywright = false) {
|
|
34
36
|
this.isPlaywright = isPlaywright;
|
|
35
37
|
}
|
|
@@ -40,30 +42,32 @@ var ContractReporter = class {
|
|
|
40
42
|
this.startTime = Date.now();
|
|
41
43
|
this.componentName = componentName;
|
|
42
44
|
this.totalTests = totalTests;
|
|
45
|
+
this.hasPrintedStaticSection = false;
|
|
46
|
+
this.hasPrintedDynamicSection = false;
|
|
43
47
|
if (apgUrl) {
|
|
44
48
|
this.apgUrl = apgUrl;
|
|
45
49
|
}
|
|
46
50
|
const mode = this.isPlaywright ? "Playwright (Real Browser)" : "jsdom (Fast)";
|
|
47
51
|
this.log(`
|
|
48
52
|
${"\u2550".repeat(60)}`);
|
|
49
|
-
this.log(`\u{1F50D} Testing ${componentName} Component - ${mode}`);
|
|
53
|
+
this.log(`\u{1F50D} Testing ${componentName.charAt(0).toUpperCase() + componentName.slice(1)} Component - ${mode}`);
|
|
50
54
|
this.log(`${"\u2550".repeat(60)}
|
|
51
55
|
`);
|
|
52
56
|
}
|
|
53
57
|
reportStatic(passes, failures) {
|
|
54
58
|
this.staticPasses = passes;
|
|
55
59
|
this.staticFailures = failures;
|
|
56
|
-
const icon = failures === 0 ? "\u2705" : "\u274C";
|
|
57
|
-
const status = failures === 0 ? "PASS" : "FAIL";
|
|
58
|
-
this.log("");
|
|
59
|
-
this.log(`${icon} Static ARIA Tests: ${status}`);
|
|
60
|
-
this.log(` ${passes}/${passes + failures} required attributes present
|
|
61
|
-
`);
|
|
62
60
|
}
|
|
63
61
|
/**
|
|
64
62
|
* Report individual static test pass
|
|
65
63
|
*/
|
|
66
64
|
reportStaticTest(description, passed, failureMessage) {
|
|
65
|
+
if (!this.hasPrintedStaticSection) {
|
|
66
|
+
this.log(`${"\u2500".repeat(60)}`);
|
|
67
|
+
this.log(`\u{1F9EA} Static Assertions`);
|
|
68
|
+
this.log(`${"\u2500".repeat(60)}`);
|
|
69
|
+
this.hasPrintedStaticSection = true;
|
|
70
|
+
}
|
|
67
71
|
const icon = passed ? "\u2713" : "\u2717";
|
|
68
72
|
this.log(` ${icon} ${description}`);
|
|
69
73
|
if (!passed && failureMessage) {
|
|
@@ -74,6 +78,13 @@ ${"\u2550".repeat(60)}`);
|
|
|
74
78
|
* Report individual dynamic test result
|
|
75
79
|
*/
|
|
76
80
|
reportTest(test, status, failureMessage) {
|
|
81
|
+
if (!this.hasPrintedDynamicSection) {
|
|
82
|
+
this.log("");
|
|
83
|
+
this.log(`${"\u2500".repeat(60)}`);
|
|
84
|
+
this.log(`\u2328\uFE0F Dynamic Interaction Tests`);
|
|
85
|
+
this.log(`${"\u2500".repeat(60)}`);
|
|
86
|
+
this.hasPrintedDynamicSection = true;
|
|
87
|
+
}
|
|
77
88
|
const result = {
|
|
78
89
|
description: test.description,
|
|
79
90
|
status,
|
|
@@ -160,7 +171,7 @@ ${"\u2500".repeat(60)}`);
|
|
|
160
171
|
});
|
|
161
172
|
this.log(`
|
|
162
173
|
\u{1F4A1} Run with Playwright for full validation:`);
|
|
163
|
-
this.log(` testUiComponent('${this.componentName}',
|
|
174
|
+
this.log(` testUiComponent('${this.componentName}', null, 'http://localhost:5173/test-harness?component=component_name')
|
|
164
175
|
`);
|
|
165
176
|
}
|
|
166
177
|
/**
|
|
@@ -184,9 +195,14 @@ ${"\u2500".repeat(60)}`);
|
|
|
184
195
|
${"\u2550".repeat(60)}`);
|
|
185
196
|
this.log(`\u{1F4CA} Summary
|
|
186
197
|
`);
|
|
198
|
+
const staticIcon = this.staticFailures === 0 ? "\u2705" : "\u274C";
|
|
199
|
+
const staticStatus = this.staticFailures === 0 ? "PASS" : "FAIL";
|
|
200
|
+
this.log(`${staticIcon} Static ARIA Tests: ${staticStatus}`);
|
|
201
|
+
this.log(` ${this.staticPasses}/${this.staticPasses + this.staticFailures} required attributes present`);
|
|
202
|
+
this.log("");
|
|
187
203
|
if (totalFailures === 0 && this.skipped === 0 && this.optionalSuggestions === 0) {
|
|
188
204
|
this.log(`\u2705 All ${totalRun} tests passed!`);
|
|
189
|
-
this.log(` ${this.componentName} component meets WAI-ARIA expectations for Roles, States, Properties, and Keyboard Interactions \u2713`);
|
|
205
|
+
this.log(` ${this.componentName.charAt(0).toUpperCase()}${this.componentName.slice(1)} component meets WAI-ARIA expectations for Roles, States, Properties, and Keyboard Interactions \u2713`);
|
|
190
206
|
} else if (totalFailures === 0) {
|
|
191
207
|
this.log(`\u2705 ${totalPasses}/${totalRun} required tests passed`);
|
|
192
208
|
if (this.skipped > 0) {
|
|
@@ -195,7 +211,7 @@ ${"\u2550".repeat(60)}`);
|
|
|
195
211
|
if (this.optionalSuggestions > 0) {
|
|
196
212
|
this.log(`\u{1F4A1} ${this.optionalSuggestions} optional enhancement${this.optionalSuggestions > 1 ? "s" : ""} suggested`);
|
|
197
213
|
}
|
|
198
|
-
this.log(` ${this.componentName} component meets WAI-ARIA expectations for Roles, States, Properties, and Keyboard Interactions \u2713`);
|
|
214
|
+
this.log(` ${this.componentName.charAt(0).toUpperCase()}${this.componentName.slice(1)} component meets WAI-ARIA expectations for Roles, States, Properties, and Keyboard Interactions \u2713`);
|
|
199
215
|
} else {
|
|
200
216
|
this.log(`\u274C ${totalFailures} test${totalFailures > 1 ? "s" : ""} failed`);
|
|
201
217
|
this.log(`\u2705 ${totalPasses} test${totalPasses > 1 ? "s" : ""} passed`);
|
|
@@ -239,7 +255,7 @@ ${"\u2550".repeat(60)}`);
|
|
|
239
255
|
}
|
|
240
256
|
};
|
|
241
257
|
|
|
242
|
-
// src/utils/test/
|
|
258
|
+
// src/utils/test/src/playwrightTestHarness.ts
|
|
243
259
|
import { chromium } from "playwright";
|
|
244
260
|
var sharedBrowser = null;
|
|
245
261
|
var sharedContext = null;
|
|
@@ -2,13 +2,13 @@ import {
|
|
|
2
2
|
ContractReporter,
|
|
3
3
|
contract_default,
|
|
4
4
|
createTestPage
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-AUJAN4RK.js";
|
|
6
6
|
import {
|
|
7
7
|
__export,
|
|
8
8
|
__reExport
|
|
9
9
|
} from "./chunk-I2KLQ2HA.js";
|
|
10
10
|
|
|
11
|
-
// src/utils/test/
|
|
11
|
+
// src/utils/test/src/contractTestRunnerPlaywright.ts
|
|
12
12
|
import { readFileSync as readFileSync2 } from "fs";
|
|
13
13
|
|
|
14
14
|
// node_modules/@playwright/test/index.mjs
|
|
@@ -233,7 +233,7 @@ var ComponentDetector = class {
|
|
|
233
233
|
const contractData = readFileSync(resolvedPath, "utf-8");
|
|
234
234
|
const componentContract = JSON.parse(contractData);
|
|
235
235
|
const selectors = componentContract.selectors;
|
|
236
|
-
if (componentName
|
|
236
|
+
if (componentName.includes("combobox")) {
|
|
237
237
|
const mainSelector = selectors.input || selectors.container;
|
|
238
238
|
return new ComboboxComponentStrategy(mainSelector, selectors, actionTimeoutMs, assertionTimeoutMs);
|
|
239
239
|
}
|
|
@@ -732,7 +732,7 @@ var AssertionRunner = class {
|
|
|
732
732
|
}
|
|
733
733
|
};
|
|
734
734
|
|
|
735
|
-
// src/utils/test/
|
|
735
|
+
// src/utils/test/src/contractTestRunnerPlaywright.ts
|
|
736
736
|
async function runContractTestsPlaywright(componentName, url) {
|
|
737
737
|
const reporter = new ContractReporter(true);
|
|
738
738
|
const actionTimeoutMs = 400;
|
|
@@ -772,7 +772,7 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
772
772
|
throw new Error(`CRITICAL: No selector found in contract for ${componentName}`);
|
|
773
773
|
}
|
|
774
774
|
try {
|
|
775
|
-
await page.locator(mainSelector).first().waitFor({ state: "attached", timeout:
|
|
775
|
+
await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: 3e4 });
|
|
776
776
|
} catch (error) {
|
|
777
777
|
throw new Error(
|
|
778
778
|
`
|
|
@@ -787,24 +787,29 @@ This usually means:
|
|
|
787
787
|
reporter.start(componentName, totalTests, apgUrl);
|
|
788
788
|
if (componentName === "menu" && componentContract.selectors.trigger) {
|
|
789
789
|
await page.locator(componentContract.selectors.trigger).first().waitFor({
|
|
790
|
-
state: "
|
|
790
|
+
state: "attached",
|
|
791
791
|
timeout: 5e3
|
|
792
792
|
}).catch(() => {
|
|
793
|
-
console.warn("Menu trigger not visible, continuing with tests...");
|
|
794
793
|
});
|
|
795
794
|
}
|
|
795
|
+
const failuresBeforeStatic = failures.length;
|
|
796
796
|
const staticAssertionRunner = new AssertionRunner(page, componentContract.selectors, assertionTimeoutMs);
|
|
797
797
|
for (const test of componentContract.static[0]?.assertions || []) {
|
|
798
798
|
if (test.target === "relative") continue;
|
|
799
|
+
const staticDescription = `${test.target}${test.attribute ? ` (${test.attribute})` : ""}`;
|
|
799
800
|
const targetSelector = componentContract.selectors[test.target];
|
|
800
801
|
if (!targetSelector) {
|
|
801
|
-
|
|
802
|
+
const failure = `Selector for target ${test.target} not found.`;
|
|
803
|
+
failures.push(failure);
|
|
804
|
+
reporter.reportStaticTest(staticDescription, false, failure);
|
|
802
805
|
continue;
|
|
803
806
|
}
|
|
804
807
|
const target = page.locator(targetSelector).first();
|
|
805
808
|
const exists = await target.count() > 0;
|
|
806
809
|
if (!exists) {
|
|
807
|
-
|
|
810
|
+
const failure = `Target ${test.target} not found.`;
|
|
811
|
+
failures.push(failure);
|
|
812
|
+
reporter.reportStaticTest(staticDescription, false, failure);
|
|
808
813
|
continue;
|
|
809
814
|
}
|
|
810
815
|
const isRedundantCheck = (selector, attrName, expectedVal) => {
|
|
@@ -838,13 +843,19 @@ This usually means:
|
|
|
838
843
|
}
|
|
839
844
|
}
|
|
840
845
|
if (!hasAny && !allRedundant) {
|
|
841
|
-
|
|
846
|
+
const failure = test.failureMessage + ` None of the attributes "${test.attribute}" are present.`;
|
|
847
|
+
failures.push(failure);
|
|
848
|
+
reporter.reportStaticTest(staticDescription, false, failure);
|
|
842
849
|
} else if (!allRedundant && hasAny) {
|
|
843
850
|
passes.push(`At least one of the attributes "${test.attribute}" exists on the element.`);
|
|
851
|
+
reporter.reportStaticTest(staticDescription, true);
|
|
852
|
+
} else {
|
|
853
|
+
reporter.reportStaticTest(staticDescription, true);
|
|
844
854
|
}
|
|
845
855
|
} else {
|
|
846
856
|
if (isRedundantCheck(targetSelector, test.attribute, test.expectedValue)) {
|
|
847
857
|
passes.push(`${test.attribute}="${test.expectedValue}" on ${test.target} verified by selector (already present in: ${targetSelector}).`);
|
|
858
|
+
reporter.reportStaticTest(staticDescription, true);
|
|
848
859
|
} else {
|
|
849
860
|
const result = await staticAssertionRunner.validateAttribute(
|
|
850
861
|
target,
|
|
@@ -856,8 +867,10 @@ This usually means:
|
|
|
856
867
|
);
|
|
857
868
|
if (result.success && result.passMessage) {
|
|
858
869
|
passes.push(result.passMessage);
|
|
870
|
+
reporter.reportStaticTest(staticDescription, true);
|
|
859
871
|
} else if (!result.success && result.failMessage) {
|
|
860
872
|
failures.push(result.failMessage);
|
|
873
|
+
reporter.reportStaticTest(staticDescription, false, result.failMessage);
|
|
861
874
|
}
|
|
862
875
|
}
|
|
863
876
|
}
|
|
@@ -936,8 +949,9 @@ This usually means:
|
|
|
936
949
|
reporter.reportTest(dynamicTest, testPassed ? "pass" : "fail", failureMessage);
|
|
937
950
|
}
|
|
938
951
|
}
|
|
939
|
-
const
|
|
940
|
-
const staticFailed =
|
|
952
|
+
const staticTotal = componentContract.static[0].assertions.length;
|
|
953
|
+
const staticFailed = failures.length - failuresBeforeStatic;
|
|
954
|
+
const staticPassed = Math.max(0, staticTotal - staticFailed);
|
|
941
955
|
reporter.reportStatic(staticPassed, staticFailed);
|
|
942
956
|
reporter.summary(failures);
|
|
943
957
|
} catch (error) {
|