aria-ease 6.4.8 → 6.5.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 (44) hide show
  1. package/README.md +15 -27
  2. package/bin/{chunk-TQBS54MM.js → chunk-AUJAN4RK.js} +35 -19
  3. package/bin/cli.cjs +952 -513
  4. package/bin/cli.js +1 -1
  5. package/bin/contractTestRunnerPlaywright-7F756CFB.js +984 -0
  6. package/bin/{test-WICJJ62P.js → test-C3CMRHSI.js} +39 -32
  7. package/dist/{chunk-TQBS54MM.js → chunk-AUJAN4RK.js} +35 -19
  8. package/dist/contractTestRunnerPlaywright-7F756CFB.js +984 -0
  9. package/dist/index.cjs +958 -519
  10. package/dist/index.js +46 -39
  11. package/dist/src/{Types.d-DYfYR3Vc.d.cts → Types.d-yGC2bBaB.d.cts} +1 -1
  12. package/dist/src/{Types.d-DYfYR3Vc.d.ts → Types.d-yGC2bBaB.d.ts} +1 -1
  13. package/dist/src/accordion/index.d.cts +1 -1
  14. package/dist/src/accordion/index.d.ts +1 -1
  15. package/dist/src/block/index.d.cts +1 -1
  16. package/dist/src/block/index.d.ts +1 -1
  17. package/dist/src/checkbox/index.d.cts +1 -1
  18. package/dist/src/checkbox/index.d.ts +1 -1
  19. package/dist/src/combobox/index.d.cts +1 -1
  20. package/dist/src/combobox/index.d.ts +1 -1
  21. package/dist/src/menu/index.cjs +7 -7
  22. package/dist/src/menu/index.d.cts +1 -1
  23. package/dist/src/menu/index.d.ts +1 -1
  24. package/dist/src/menu/index.js +7 -7
  25. package/dist/src/radio/index.d.cts +1 -1
  26. package/dist/src/radio/index.d.ts +1 -1
  27. package/dist/src/tabs/index.d.cts +1 -1
  28. package/dist/src/tabs/index.d.ts +1 -1
  29. package/dist/src/toggle/index.d.cts +1 -1
  30. package/dist/src/toggle/index.d.ts +1 -1
  31. package/dist/src/utils/test/{contracts/AccordionContract.json → aria-contracts/accordion/accordion.contract.json} +20 -7
  32. package/dist/src/utils/test/{contracts/ComboboxContract.json → aria-contracts/combobox/combobox.listbox.contract.json} +18 -17
  33. package/dist/src/utils/test/{contracts/MenuContract.json → aria-contracts/menu/menu.contract.json} +42 -1
  34. package/dist/src/utils/test/{contracts/TabsContract.json → aria-contracts/tabs/tabs.contract.json} +20 -7
  35. package/dist/src/utils/test/{chunk-TQBS54MM.js → chunk-AUJAN4RK.js} +34 -18
  36. package/dist/src/utils/test/contractTestRunnerPlaywright-HL73FADJ.js +955 -0
  37. package/dist/src/utils/test/index.cjs +921 -505
  38. package/dist/src/utils/test/index.d.cts +6 -1
  39. package/dist/src/utils/test/index.d.ts +6 -1
  40. package/dist/src/utils/test/index.js +38 -31
  41. package/package.json +2 -2
  42. package/bin/contractTestRunnerPlaywright-D57V4RSU.js +0 -628
  43. package/dist/contractTestRunnerPlaywright-D57V4RSU.js +0 -628
  44. package/dist/src/utils/test/contractTestRunnerPlaywright-HV4EIRDH.js +0 -610
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Aria-Ease
2
2
 
3
- **Accessibility infrastructure for the entire frontend engineering lifecycle.**
3
+ ### Accessibility infrastructure for the entire frontend engineering lifecycle.
4
4
 
5
- Stop treating accessibility as an afterthought. Aria-Ease engineers technical integrity into every phase of frontend development — from local development to production monitoring — so accessibility violations never reach your users.
5
+ Stop treating accessibility as an afterthought. Aria-Ease engineers accessibility integrity into every phase of frontend development lifecycle — from local development to production monitoring — so accessibility violations never reach your users.
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/aria-ease.svg)](https://www.npmjs.com/package/aria-ease)
8
8
  [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
@@ -64,13 +64,14 @@ npx aria-ease audit --url https://yoursite.com
64
64
 
65
65
  #### 3. **Contract Testing** (Available Now)
66
66
 
67
- This is the game-changer. We encoded the WAI-ARIA APG into deterministic JSON "contracts" and built a custom Playwright runner with isolated test-harness architecture.
67
+ This is the game-changer. We encoded the WAI-ARIA APG into deterministic JSON "contracts" and built a custom Playwright runner with isolated test-harness architecture. Run it locally or in CI/CD.
68
68
 
69
69
  **The result?** Component interaction testing that feels closer to unit testing than manual QA.
70
70
 
71
71
  ```bash
72
- npx aria-ease test --component combobox --url http://localhost:3000
72
+ npx aria-ease test
73
73
  # ✓ 26 assertions in ~4 seconds
74
+ # ✓ 26 assertions in ~1 second in CI
74
75
  ```
75
76
 
76
77
  **Why this matters:** Before, verifying a combobox meant manual keyboard testing across browsers. Now, it's automated, fast, and repeatable. You can boast about executing 26 combobox interaction assertions in ~4 seconds.
@@ -650,7 +651,7 @@ describe("Shopify User Menu Accessibility Test", () => {
650
651
  null,
651
652
  "http://localhost:5173/test-harness?component=menu",
652
653
  ); // For full component interaction test. Uses Playwright to test interaction and behaviors
653
- }, 6000);
654
+ });
654
655
  });
655
656
 
656
657
  describe("Shopify User Menu Accessibility Test", () => {
@@ -764,7 +765,7 @@ Until now, accessibility testing often happened manually, late in the cycle, or
764
765
  **Aria-Ease changes the equation:**
765
766
 
766
767
  - ✅ Automated = no human bottleneck
767
- - ✅ Fast = ~4 seconds for comprehensive component testing
768
+ - ✅ Fast = ~6 seconds for 90 accessibility interaction assertions
768
769
  - ✅ Deterministic = same results every time
769
770
  - ✅ Blocking = deploy fails if tests fail
770
771
 
@@ -875,21 +876,12 @@ Create `ariaease.config.js` in your project root:
875
876
  ```javascript
876
877
  export default {
877
878
  audit: {
878
- urls: [
879
- "http://localhost:5173", // Homepage
880
- "http://localhost:5173/docs", // Docs
881
- "http://localhost:5173/examples", // Examples
882
- ],
879
+ urls: ["http://localhost:5173/", "http://localhost:5173/changelog"],
883
880
  output: {
884
- format: "all", // Generate JSON, CSV, and HTML reports
885
- out: "./accessibility-reports",
881
+ format: "html",
882
+ out: "./accessibility-reports/audit",
886
883
  },
887
884
  },
888
- test: {
889
- components: ["menu", "accordion", "tabs", "combobox"], // Components to test
890
- baseUrl: "http://localhost:5173/test-harness",
891
- browser: "chromium",
892
- },
893
885
  };
894
886
  ```
895
887
 
@@ -898,8 +890,8 @@ Add to `package.json`:
898
890
  ```json
899
891
  {
900
892
  "scripts": {
901
- "audit": "aria-ease audit",
902
- "test:a11y": "aria-ease test",
893
+ "audit": "npx aria-ease audit -f html",
894
+ "test:a11y": "npx aria-ease test",
903
895
  "ci": "npm run audit && npm run test:a11y"
904
896
  }
905
897
  }
@@ -980,14 +972,10 @@ One of the biggest blockers to adding accessibility testing to CI/CD is **speed*
980
972
  **Aria-Ease contract testing is fast:**
981
973
 
982
974
  ```bash
983
- npx aria-ease test --component combobox
984
- # ✓ 26 interaction assertions in ~4 seconds
985
-
986
- npx aria-ease test --component menu
987
- # ✓ 15 interaction assertions in ~2.8 seconds
975
+ npx aria-ease test
976
+ # ✓ 26 combobox interaction assertions in ~1 seconds in CI
977
+ # ✓ 90 accessibility interaction assertions in ~6 seconds in CI
988
978
 
989
- npx aria-ease test # All components
990
- # ✓ 80+ assertions in ~12 seconds
991
979
  ```
992
980
 
993
981
  **Why so fast?**
@@ -1,24 +1,24 @@
1
1
  // src/utils/test/contract/contract.json
2
2
  var contract_default = {
3
3
  menu: {
4
- path: "./contracts/MenuContract.json",
4
+ path: "./aria-contracts/menu/menu.contract.json",
5
5
  component: "menu"
6
6
  },
7
- combobox: {
8
- path: "./contracts/ComboboxContract.json",
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/AccordionContract.json",
12
+ path: "./aria-contracts/accordion/accordion.contract.json",
13
13
  component: "accordion"
14
14
  },
15
15
  tabs: {
16
- path: "./contracts/TabsContract.json",
16
+ path: "./aria-contracts/tabs/tabs.contract.json",
17
17
  component: "tabs"
18
18
  }
19
19
  };
20
20
 
21
- // src/utils/test/contract/ContractReporter.ts
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,13 +78,20 @@ ${"\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,
80
91
  failureMessage,
81
92
  isOptional: test.isOptional
82
93
  };
83
- if (status === "skip" && test.requiresBrowser) {
94
+ if (status === "skip") {
84
95
  result.skipReason = "Requires real browser (addEventListener events)";
85
96
  }
86
97
  this.dynamicResults.push(result);
@@ -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}', component, 'http://localhost:5173/')
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 Interaction \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 Interaction \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/contract/playwrightTestHarness.ts
258
+ // src/utils/test/src/playwrightTestHarness.ts
243
259
  import { chromium } from "playwright";
244
260
  var sharedBrowser = null;
245
261
  var sharedContext = null;