aria-ease 6.4.10 → 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 (38) hide show
  1. package/bin/{chunk-GFKAJHCS.js → chunk-AUJAN4RK.js} +34 -18
  2. package/bin/cli.cjs +67 -35
  3. package/bin/cli.js +1 -1
  4. package/{dist/contractTestRunnerPlaywright-7BCEDPZF.js → bin/contractTestRunnerPlaywright-7F756CFB.js} +26 -12
  5. package/bin/{test-JGKWOL6J.js → test-C3CMRHSI.js} +7 -5
  6. package/dist/{chunk-GFKAJHCS.js → chunk-AUJAN4RK.js} +34 -18
  7. package/{bin/contractTestRunnerPlaywright-7BCEDPZF.js → dist/contractTestRunnerPlaywright-7F756CFB.js} +26 -12
  8. package/dist/index.cjs +73 -41
  9. package/dist/index.js +14 -12
  10. package/dist/src/{Types.d-DYfYR3Vc.d.cts → Types.d-yGC2bBaB.d.cts} +1 -1
  11. package/dist/src/{Types.d-DYfYR3Vc.d.ts → Types.d-yGC2bBaB.d.ts} +1 -1
  12. package/dist/src/accordion/index.d.cts +1 -1
  13. package/dist/src/accordion/index.d.ts +1 -1
  14. package/dist/src/block/index.d.cts +1 -1
  15. package/dist/src/block/index.d.ts +1 -1
  16. package/dist/src/checkbox/index.d.cts +1 -1
  17. package/dist/src/checkbox/index.d.ts +1 -1
  18. package/dist/src/combobox/index.d.cts +1 -1
  19. package/dist/src/combobox/index.d.ts +1 -1
  20. package/dist/src/menu/index.cjs +7 -7
  21. package/dist/src/menu/index.d.cts +1 -1
  22. package/dist/src/menu/index.d.ts +1 -1
  23. package/dist/src/menu/index.js +7 -7
  24. package/dist/src/radio/index.d.cts +1 -1
  25. package/dist/src/radio/index.d.ts +1 -1
  26. package/dist/src/tabs/index.d.cts +1 -1
  27. package/dist/src/tabs/index.d.ts +1 -1
  28. package/dist/src/toggle/index.d.cts +1 -1
  29. package/dist/src/toggle/index.d.ts +1 -1
  30. package/dist/src/utils/test/{contracts/AccordionContract.json → aria-contracts/accordion/accordion.contract.json} +20 -7
  31. package/dist/src/utils/test/{contracts/ComboboxContract.json → aria-contracts/combobox/combobox.listbox.contract.json} +17 -17
  32. package/dist/src/utils/test/{contracts/MenuContract.json → aria-contracts/menu/menu.contract.json} +42 -1
  33. package/dist/src/utils/test/{contracts/TabsContract.json → aria-contracts/tabs/tabs.contract.json} +20 -7
  34. package/dist/src/utils/test/{chunk-GFKAJHCS.js → chunk-AUJAN4RK.js} +33 -17
  35. package/dist/src/utils/test/{contractTestRunnerPlaywright-O7FF3X67.js → contractTestRunnerPlaywright-HL73FADJ.js} +25 -11
  36. package/dist/src/utils/test/index.cjs +65 -33
  37. package/dist/src/utils/test/index.js +6 -4
  38. package/package.json +2 -2
@@ -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,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}', 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 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/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;
package/bin/cli.cjs CHANGED
@@ -403,29 +403,29 @@ var init_contract = __esm({
403
403
  "src/utils/test/contract/contract.json"() {
404
404
  contract_default = {
405
405
  menu: {
406
- path: "./contracts/MenuContract.json",
406
+ path: "./aria-contracts/menu/menu.contract.json",
407
407
  component: "menu"
408
408
  },
409
- combobox: {
410
- path: "./contracts/ComboboxContract.json",
411
- component: "combobox"
409
+ "combobox.listbox": {
410
+ path: "./aria-contracts/combobox/combobox.listbox.contract.json",
411
+ component: "combobox.listbox"
412
412
  },
413
413
  accordion: {
414
- path: "./contracts/AccordionContract.json",
414
+ path: "./aria-contracts/accordion/accordion.contract.json",
415
415
  component: "accordion"
416
416
  },
417
417
  tabs: {
418
- path: "./contracts/TabsContract.json",
418
+ path: "./aria-contracts/tabs/tabs.contract.json",
419
419
  component: "tabs"
420
420
  }
421
421
  };
422
422
  }
423
423
  });
424
424
 
425
- // src/utils/test/contract/ContractReporter.ts
425
+ // src/utils/test/src/ContractReporter.ts
426
426
  var ContractReporter;
427
427
  var init_ContractReporter = __esm({
428
- "src/utils/test/contract/ContractReporter.ts"() {
428
+ "src/utils/test/src/ContractReporter.ts"() {
429
429
  "use strict";
430
430
  ContractReporter = class {
431
431
  startTime = 0;
@@ -438,6 +438,8 @@ var init_ContractReporter = __esm({
438
438
  optionalSuggestions = 0;
439
439
  isPlaywright = false;
440
440
  apgUrl = "https://www.w3.org/WAI/ARIA/apg/";
441
+ hasPrintedStaticSection = false;
442
+ hasPrintedDynamicSection = false;
441
443
  constructor(isPlaywright = false) {
442
444
  this.isPlaywright = isPlaywright;
443
445
  }
@@ -448,30 +450,32 @@ var init_ContractReporter = __esm({
448
450
  this.startTime = Date.now();
449
451
  this.componentName = componentName;
450
452
  this.totalTests = totalTests;
453
+ this.hasPrintedStaticSection = false;
454
+ this.hasPrintedDynamicSection = false;
451
455
  if (apgUrl) {
452
456
  this.apgUrl = apgUrl;
453
457
  }
454
458
  const mode = this.isPlaywright ? "Playwright (Real Browser)" : "jsdom (Fast)";
455
459
  this.log(`
456
460
  ${"\u2550".repeat(60)}`);
457
- this.log(`\u{1F50D} Testing ${componentName} Component - ${mode}`);
461
+ this.log(`\u{1F50D} Testing ${componentName.charAt(0).toUpperCase() + componentName.slice(1)} Component - ${mode}`);
458
462
  this.log(`${"\u2550".repeat(60)}
459
463
  `);
460
464
  }
461
465
  reportStatic(passes, failures) {
462
466
  this.staticPasses = passes;
463
467
  this.staticFailures = failures;
464
- const icon = failures === 0 ? "\u2705" : "\u274C";
465
- const status = failures === 0 ? "PASS" : "FAIL";
466
- this.log("");
467
- this.log(`${icon} Static ARIA Tests: ${status}`);
468
- this.log(` ${passes}/${passes + failures} required attributes present
469
- `);
470
468
  }
471
469
  /**
472
470
  * Report individual static test pass
473
471
  */
474
472
  reportStaticTest(description, passed, failureMessage) {
473
+ if (!this.hasPrintedStaticSection) {
474
+ this.log(`${"\u2500".repeat(60)}`);
475
+ this.log(`\u{1F9EA} Static Assertions`);
476
+ this.log(`${"\u2500".repeat(60)}`);
477
+ this.hasPrintedStaticSection = true;
478
+ }
475
479
  const icon = passed ? "\u2713" : "\u2717";
476
480
  this.log(` ${icon} ${description}`);
477
481
  if (!passed && failureMessage) {
@@ -482,6 +486,13 @@ ${"\u2550".repeat(60)}`);
482
486
  * Report individual dynamic test result
483
487
  */
484
488
  reportTest(test, status, failureMessage) {
489
+ if (!this.hasPrintedDynamicSection) {
490
+ this.log("");
491
+ this.log(`${"\u2500".repeat(60)}`);
492
+ this.log(`\u2328\uFE0F Dynamic Interaction Tests`);
493
+ this.log(`${"\u2500".repeat(60)}`);
494
+ this.hasPrintedDynamicSection = true;
495
+ }
485
496
  const result = {
486
497
  description: test.description,
487
498
  status,
@@ -568,7 +579,7 @@ ${"\u2500".repeat(60)}`);
568
579
  });
569
580
  this.log(`
570
581
  \u{1F4A1} Run with Playwright for full validation:`);
571
- this.log(` testUiComponent('${this.componentName}', component, 'http://localhost:5173/')
582
+ this.log(` testUiComponent('${this.componentName}', null, 'http://localhost:5173/test-harness?component=component_name')
572
583
  `);
573
584
  }
574
585
  /**
@@ -592,9 +603,14 @@ ${"\u2500".repeat(60)}`);
592
603
  ${"\u2550".repeat(60)}`);
593
604
  this.log(`\u{1F4CA} Summary
594
605
  `);
606
+ const staticIcon = this.staticFailures === 0 ? "\u2705" : "\u274C";
607
+ const staticStatus = this.staticFailures === 0 ? "PASS" : "FAIL";
608
+ this.log(`${staticIcon} Static ARIA Tests: ${staticStatus}`);
609
+ this.log(` ${this.staticPasses}/${this.staticPasses + this.staticFailures} required attributes present`);
610
+ this.log("");
595
611
  if (totalFailures === 0 && this.skipped === 0 && this.optionalSuggestions === 0) {
596
612
  this.log(`\u2705 All ${totalRun} tests passed!`);
597
- this.log(` ${this.componentName} component meets WAI-ARIA expectations for Roles, States, Properties, and Keyboard Interactions \u2713`);
613
+ this.log(` ${this.componentName.charAt(0).toUpperCase()}${this.componentName.slice(1)} component meets WAI-ARIA expectations for Roles, States, Properties, and Keyboard Interactions \u2713`);
598
614
  } else if (totalFailures === 0) {
599
615
  this.log(`\u2705 ${totalPasses}/${totalRun} required tests passed`);
600
616
  if (this.skipped > 0) {
@@ -603,7 +619,7 @@ ${"\u2550".repeat(60)}`);
603
619
  if (this.optionalSuggestions > 0) {
604
620
  this.log(`\u{1F4A1} ${this.optionalSuggestions} optional enhancement${this.optionalSuggestions > 1 ? "s" : ""} suggested`);
605
621
  }
606
- this.log(` ${this.componentName} component meets WAI-ARIA expectations for Roles, States, Properties, and Keyboard Interactions \u2713`);
622
+ this.log(` ${this.componentName.charAt(0).toUpperCase()}${this.componentName.slice(1)} component meets WAI-ARIA expectations for Roles, States, Properties, and Keyboard Interactions \u2713`);
607
623
  } else {
608
624
  this.log(`\u274C ${totalFailures} test${totalFailures > 1 ? "s" : ""} failed`);
609
625
  this.log(`\u2705 ${totalPasses} test${totalPasses > 1 ? "s" : ""} passed`);
@@ -649,7 +665,7 @@ ${"\u2550".repeat(60)}`);
649
665
  }
650
666
  });
651
667
 
652
- // src/utils/test/contract/contractTestRunner.ts
668
+ // src/utils/test/src/contractTestRunner.ts
653
669
  async function runContractTests(componentName, component) {
654
670
  const reporter = new ContractReporter(false);
655
671
  const contractTyped = contract_default;
@@ -665,6 +681,7 @@ async function runContractTests(componentName, component) {
665
681
  const failures = [];
666
682
  const passes = [];
667
683
  const skipped = [];
684
+ const failuresBeforeStatic = failures.length;
668
685
  for (const test of componentContract.static[0].assertions) {
669
686
  if (test.target !== "relative") {
670
687
  const selector = componentContract.selectors[test.target];
@@ -703,15 +720,16 @@ async function runContractTests(componentName, component) {
703
720
  skipped.push(dynamicTest.description);
704
721
  reporter.reportTest(dynamicTest, "skip");
705
722
  }
706
- const staticPassed = componentContract.static[0].assertions.length;
707
- const staticFailed = 0;
723
+ const staticTotal = componentContract.static[0].assertions.length;
724
+ const staticFailed = failures.length - failuresBeforeStatic;
725
+ const staticPassed = Math.max(0, staticTotal - staticFailed);
708
726
  reporter.reportStatic(staticPassed, staticFailed);
709
727
  reporter.summary(failures);
710
728
  return { passes, failures, skipped };
711
729
  }
712
730
  var import_promises, import_meta;
713
731
  var init_contractTestRunner = __esm({
714
- "src/utils/test/contract/contractTestRunner.ts"() {
732
+ "src/utils/test/src/contractTestRunner.ts"() {
715
733
  "use strict";
716
734
  init_contract();
717
735
  import_promises = __toESM(require("fs/promises"), 1);
@@ -720,7 +738,7 @@ var init_contractTestRunner = __esm({
720
738
  }
721
739
  });
722
740
 
723
- // src/utils/test/contract/playwrightTestHarness.ts
741
+ // src/utils/test/src/playwrightTestHarness.ts
724
742
  async function getOrCreateBrowser() {
725
743
  if (!sharedBrowser) {
726
744
  sharedBrowser = await import_playwright3.chromium.launch({
@@ -762,7 +780,7 @@ async function closeSharedBrowser() {
762
780
  }
763
781
  var import_playwright3, sharedBrowser, sharedContext;
764
782
  var init_playwrightTestHarness = __esm({
765
- "src/utils/test/contract/playwrightTestHarness.ts"() {
783
+ "src/utils/test/src/playwrightTestHarness.ts"() {
766
784
  "use strict";
767
785
  import_playwright3 = require("playwright");
768
786
  sharedBrowser = null;
@@ -1034,7 +1052,7 @@ var init_ComponentDetector = __esm({
1034
1052
  const contractData = (0, import_fs.readFileSync)(resolvedPath, "utf-8");
1035
1053
  const componentContract = JSON.parse(contractData);
1036
1054
  const selectors = componentContract.selectors;
1037
- if (componentName === "combobox") {
1055
+ if (componentName.includes("combobox")) {
1038
1056
  const mainSelector = selectors.input || selectors.container;
1039
1057
  return new ComboboxComponentStrategy(mainSelector, selectors, actionTimeoutMs, assertionTimeoutMs);
1040
1058
  }
@@ -1556,7 +1574,7 @@ var init_AssertionRunner = __esm({
1556
1574
  }
1557
1575
  });
1558
1576
 
1559
- // src/utils/test/contract/contractTestRunnerPlaywright.ts
1577
+ // src/utils/test/src/contractTestRunnerPlaywright.ts
1560
1578
  var contractTestRunnerPlaywright_exports = {};
1561
1579
  __export(contractTestRunnerPlaywright_exports, {
1562
1580
  runContractTestsPlaywright: () => runContractTestsPlaywright
@@ -1600,7 +1618,7 @@ async function runContractTestsPlaywright(componentName, url) {
1600
1618
  throw new Error(`CRITICAL: No selector found in contract for ${componentName}`);
1601
1619
  }
1602
1620
  try {
1603
- await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: 28e3 });
1621
+ await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: 3e4 });
1604
1622
  } catch (error) {
1605
1623
  throw new Error(
1606
1624
  `
@@ -1615,24 +1633,29 @@ This usually means:
1615
1633
  reporter.start(componentName, totalTests, apgUrl);
1616
1634
  if (componentName === "menu" && componentContract.selectors.trigger) {
1617
1635
  await page.locator(componentContract.selectors.trigger).first().waitFor({
1618
- state: "visible",
1636
+ state: "attached",
1619
1637
  timeout: 5e3
1620
1638
  }).catch(() => {
1621
- console.warn("Menu trigger not visible, continuing with tests...");
1622
1639
  });
1623
1640
  }
1641
+ const failuresBeforeStatic = failures.length;
1624
1642
  const staticAssertionRunner = new AssertionRunner(page, componentContract.selectors, assertionTimeoutMs);
1625
1643
  for (const test of componentContract.static[0]?.assertions || []) {
1626
1644
  if (test.target === "relative") continue;
1645
+ const staticDescription = `${test.target}${test.attribute ? ` (${test.attribute})` : ""}`;
1627
1646
  const targetSelector = componentContract.selectors[test.target];
1628
1647
  if (!targetSelector) {
1629
- failures.push(`Selector for target ${test.target} not found.`);
1648
+ const failure = `Selector for target ${test.target} not found.`;
1649
+ failures.push(failure);
1650
+ reporter.reportStaticTest(staticDescription, false, failure);
1630
1651
  continue;
1631
1652
  }
1632
1653
  const target = page.locator(targetSelector).first();
1633
1654
  const exists = await target.count() > 0;
1634
1655
  if (!exists) {
1635
- failures.push(`Target ${test.target} not found.`);
1656
+ const failure = `Target ${test.target} not found.`;
1657
+ failures.push(failure);
1658
+ reporter.reportStaticTest(staticDescription, false, failure);
1636
1659
  continue;
1637
1660
  }
1638
1661
  const isRedundantCheck = (selector, attrName, expectedVal) => {
@@ -1666,13 +1689,19 @@ This usually means:
1666
1689
  }
1667
1690
  }
1668
1691
  if (!hasAny && !allRedundant) {
1669
- failures.push(test.failureMessage + ` None of the attributes "${test.attribute}" are present.`);
1692
+ const failure = test.failureMessage + ` None of the attributes "${test.attribute}" are present.`;
1693
+ failures.push(failure);
1694
+ reporter.reportStaticTest(staticDescription, false, failure);
1670
1695
  } else if (!allRedundant && hasAny) {
1671
1696
  passes.push(`At least one of the attributes "${test.attribute}" exists on the element.`);
1697
+ reporter.reportStaticTest(staticDescription, true);
1698
+ } else {
1699
+ reporter.reportStaticTest(staticDescription, true);
1672
1700
  }
1673
1701
  } else {
1674
1702
  if (isRedundantCheck(targetSelector, test.attribute, test.expectedValue)) {
1675
1703
  passes.push(`${test.attribute}="${test.expectedValue}" on ${test.target} verified by selector (already present in: ${targetSelector}).`);
1704
+ reporter.reportStaticTest(staticDescription, true);
1676
1705
  } else {
1677
1706
  const result = await staticAssertionRunner.validateAttribute(
1678
1707
  target,
@@ -1684,8 +1713,10 @@ This usually means:
1684
1713
  );
1685
1714
  if (result.success && result.passMessage) {
1686
1715
  passes.push(result.passMessage);
1716
+ reporter.reportStaticTest(staticDescription, true);
1687
1717
  } else if (!result.success && result.failMessage) {
1688
1718
  failures.push(result.failMessage);
1719
+ reporter.reportStaticTest(staticDescription, false, result.failMessage);
1689
1720
  }
1690
1721
  }
1691
1722
  }
@@ -1764,8 +1795,9 @@ This usually means:
1764
1795
  reporter.reportTest(dynamicTest, testPassed ? "pass" : "fail", failureMessage);
1765
1796
  }
1766
1797
  }
1767
- const staticPassed = componentContract.static[0].assertions.length;
1768
- const staticFailed = 0;
1798
+ const staticTotal = componentContract.static[0].assertions.length;
1799
+ const staticFailed = failures.length - failuresBeforeStatic;
1800
+ const staticPassed = Math.max(0, staticTotal - staticFailed);
1769
1801
  reporter.reportStatic(staticPassed, staticFailed);
1770
1802
  reporter.summary(failures);
1771
1803
  } catch (error) {
@@ -1795,7 +1827,7 @@ Make sure your dev server is running at ${url}`);
1795
1827
  }
1796
1828
  var import_fs2, import_meta3;
1797
1829
  var init_contractTestRunnerPlaywright = __esm({
1798
- "src/utils/test/contract/contractTestRunnerPlaywright.ts"() {
1830
+ "src/utils/test/src/contractTestRunnerPlaywright.ts"() {
1799
1831
  "use strict";
1800
1832
  import_fs2 = require("fs");
1801
1833
  init_contract();
package/bin/cli.js CHANGED
@@ -237,7 +237,7 @@ program.command("audit").description("Run axe-core powered accessibility audit o
237
237
  process.exit(1);
238
238
  });
239
239
  program.command("test").description("Run core a11y accessibility standard tests on UI components").action(async () => {
240
- const { runTest } = await import("./test-JGKWOL6J.js");
240
+ const { runTest } = await import("./test-C3CMRHSI.js");
241
241
  runTest();
242
242
  });
243
243
  program.command("help").description("Display help information").action(() => {
@@ -2,13 +2,13 @@ import {
2
2
  ContractReporter,
3
3
  contract_default,
4
4
  createTestPage
5
- } from "./chunk-GFKAJHCS.js";
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/contract/contractTestRunnerPlaywright.ts
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 === "combobox") {
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/contract/contractTestRunnerPlaywright.ts
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: 28e3 });
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: "visible",
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
- failures.push(`Selector for target ${test.target} not found.`);
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
- failures.push(`Target ${test.target} not found.`);
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
- failures.push(test.failureMessage + ` None of the attributes "${test.attribute}" are present.`);
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 staticPassed = componentContract.static[0].assertions.length;
940
- const staticFailed = 0;
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) {
@@ -2,13 +2,13 @@ import {
2
2
  ContractReporter,
3
3
  closeSharedBrowser,
4
4
  contract_default
5
- } from "./chunk-GFKAJHCS.js";
5
+ } from "./chunk-AUJAN4RK.js";
6
6
  import "./chunk-I2KLQ2HA.js";
7
7
 
8
8
  // src/utils/test/src/test.ts
9
9
  import { axe } from "jest-axe";
10
10
 
11
- // src/utils/test/contract/contractTestRunner.ts
11
+ // src/utils/test/src/contractTestRunner.ts
12
12
  import fs from "fs/promises";
13
13
  async function runContractTests(componentName, component) {
14
14
  const reporter = new ContractReporter(false);
@@ -25,6 +25,7 @@ async function runContractTests(componentName, component) {
25
25
  const failures = [];
26
26
  const passes = [];
27
27
  const skipped = [];
28
+ const failuresBeforeStatic = failures.length;
28
29
  for (const test of componentContract.static[0].assertions) {
29
30
  if (test.target !== "relative") {
30
31
  const selector = componentContract.selectors[test.target];
@@ -63,8 +64,9 @@ async function runContractTests(componentName, component) {
63
64
  skipped.push(dynamicTest.description);
64
65
  reporter.reportTest(dynamicTest, "skip");
65
66
  }
66
- const staticPassed = componentContract.static[0].assertions.length;
67
- const staticFailed = 0;
67
+ const staticTotal = componentContract.static[0].assertions.length;
68
+ const staticFailed = failures.length - failuresBeforeStatic;
69
+ const staticPassed = Math.max(0, staticTotal - staticFailed);
68
70
  reporter.reportStatic(staticPassed, staticFailed);
69
71
  reporter.summary(failures);
70
72
  return { passes, failures, skipped };
@@ -114,7 +116,7 @@ Error: ${error instanceof Error ? error.message : String(error)}`
114
116
  const devServerUrl = await checkDevServer(url);
115
117
  if (devServerUrl) {
116
118
  console.log(`\u{1F3AD} Running Playwright tests on ${devServerUrl}`);
117
- const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-7BCEDPZF.js");
119
+ const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-7F756CFB.js");
118
120
  contract = await runContractTestsPlaywright(componentName, devServerUrl);
119
121
  } else {
120
122
  throw new Error(