aria-ease 2.8.4 → 2.9.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 (43) hide show
  1. package/bin/{audit-XABLAI36.js → audit-XZJXMUPL.js} +2 -3
  2. package/bin/{chunk-JGKPHTSR.js → chunk-5Z7PR3VC.js} +4 -0
  3. package/bin/cli.cjs +197 -50
  4. package/bin/cli.js +4 -4
  5. package/bin/{contractTestRunnerPlaywright-VDTXMVK5.js → contractTestRunnerPlaywright-62LXHK7K.js} +111 -12
  6. package/bin/{formatters-2RPHPXW2.js → formatters-U4E5EVPL.js} +23 -16
  7. package/bin/{test-N6M7MDBZ.js → test-PK5MBHIN.js} +55 -17
  8. package/dist/{chunk-SSBW5VAA.js → chunk-57O4KFP4.js} +4 -0
  9. package/dist/{contractTestRunnerPlaywright-AJ2DOOJT.js → contractTestRunnerPlaywright-LGXSV2ZS.js} +111 -12
  10. package/dist/index.cjs +409 -26
  11. package/dist/index.d.cts +27 -1
  12. package/dist/index.d.ts +27 -1
  13. package/dist/index.js +296 -17
  14. package/dist/src/Types.d-uG0Hm1yK.d.cts +39 -0
  15. package/dist/src/Types.d-uG0Hm1yK.d.ts +39 -0
  16. package/dist/src/accordion/index.d.cts +1 -1
  17. package/dist/src/accordion/index.d.ts +1 -1
  18. package/dist/src/block/index.d.cts +1 -1
  19. package/dist/src/block/index.d.ts +1 -1
  20. package/dist/src/checkbox/index.d.cts +1 -1
  21. package/dist/src/checkbox/index.d.ts +1 -1
  22. package/dist/src/combobox/index.cjs +243 -0
  23. package/dist/src/combobox/index.d.cts +14 -0
  24. package/dist/src/combobox/index.d.ts +14 -0
  25. package/dist/src/combobox/index.js +241 -0
  26. package/dist/src/menu/index.d.cts +1 -1
  27. package/dist/src/menu/index.d.ts +1 -1
  28. package/dist/src/radio/index.d.cts +1 -1
  29. package/dist/src/radio/index.d.ts +1 -1
  30. package/dist/src/toggle/index.d.cts +1 -1
  31. package/dist/src/toggle/index.d.ts +1 -1
  32. package/dist/src/utils/test/{chunk-SSBW5VAA.js → chunk-57O4KFP4.js} +4 -0
  33. package/dist/src/utils/test/{contractTestRunnerPlaywright-AJ2DOOJT.js → contractTestRunnerPlaywright-LGXSV2ZS.js} +111 -12
  34. package/dist/src/utils/test/contracts/ComboboxContract.json +474 -0
  35. package/dist/src/utils/test/index.cjs +167 -26
  36. package/dist/src/utils/test/index.js +55 -17
  37. package/package.json +9 -3
  38. package/bin/contractTestRunnerPlaywright-EHQAMXQA.js +0 -258
  39. package/bin/test-S2U633GD.js +0 -12804
  40. package/dist/contractTestRunnerPlaywright-7O2T4JES.js +0 -257
  41. package/dist/src/Types.d-w1KLKLcA.d.cts +0 -24
  42. package/dist/src/Types.d-w1KLKLcA.d.ts +0 -24
  43. package/dist/src/utils/test/contractTestRunnerPlaywright-7O2T4JES.js +0 -252
@@ -1,6 +1,6 @@
1
1
  import "./chunk-JSBRDJBE.js";
2
2
 
3
- // src/utils/audit/src/audit/audit.js
3
+ // src/utils/audit/src/audit/audit.ts
4
4
  import AxeBuilder from "@axe-core/playwright";
5
5
  import { chromium } from "playwright";
6
6
  async function runAudit(url, options) {
@@ -38,8 +38,7 @@ async function runAudit(url, options) {
38
38
  }
39
39
  throw error;
40
40
  } finally {
41
- if (browser)
42
- await browser.close();
41
+ if (browser) await browser.close();
43
42
  }
44
43
  }
45
44
  export {
@@ -3,6 +3,10 @@ var contract_default = {
3
3
  menu: {
4
4
  path: "./contracts/MenuContract.json",
5
5
  component: "menu"
6
+ },
7
+ combobox: {
8
+ path: "./contracts/ComboboxContract.json",
9
+ component: "combobox"
6
10
  }
7
11
  };
8
12
 
package/bin/cli.cjs CHANGED
@@ -33,7 +33,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
33
33
  mod
34
34
  ));
35
35
 
36
- // src/utils/audit/src/audit/audit.js
36
+ // src/utils/audit/src/audit/audit.ts
37
37
  var audit_exports = {};
38
38
  __export(audit_exports, {
39
39
  runAudit: () => runAudit
@@ -73,20 +73,19 @@ async function runAudit(url, options) {
73
73
  }
74
74
  throw error;
75
75
  } finally {
76
- if (browser)
77
- await browser.close();
76
+ if (browser) await browser.close();
78
77
  }
79
78
  }
80
79
  var import_playwright, import_playwright2;
81
80
  var init_audit = __esm({
82
- "src/utils/audit/src/audit/audit.js"() {
81
+ "src/utils/audit/src/audit/audit.ts"() {
83
82
  "use strict";
84
83
  import_playwright = __toESM(require("@axe-core/playwright"), 1);
85
84
  import_playwright2 = require("playwright");
86
85
  }
87
86
  });
88
87
 
89
- // src/utils/audit/src/formatters/formatters.js
88
+ // src/utils/audit/src/formatters/formatters.ts
90
89
  var formatters_exports = {};
91
90
  __export(formatters_exports, {
92
91
  formatResults: () => formatResults
@@ -94,14 +93,22 @@ __export(formatters_exports, {
94
93
  function formatResults(allResults, format2) {
95
94
  switch (format2) {
96
95
  case "json":
97
- return JSON.stringify(allResults.flatMap(({ url, result }) => result ? result.violations.flatMap((v) => v.nodes.map((n) => ({
98
- URL: url,
99
- Rule: v.id,
100
- Impact: v.impact,
101
- Description: v.description,
102
- Target: n.target,
103
- FailureSummary: n.failureSummary
104
- }))) : []), null, 2);
96
+ return JSON.stringify(
97
+ allResults.flatMap(
98
+ ({ url, result }) => result ? result.violations.flatMap(
99
+ (v) => v.nodes.map((n) => ({
100
+ URL: url,
101
+ Rule: v.id,
102
+ Impact: v.impact,
103
+ Description: v.description,
104
+ Target: n.target,
105
+ FailureSummary: n.failureSummary
106
+ }))
107
+ ) : []
108
+ ),
109
+ null,
110
+ 2
111
+ );
105
112
  case "csv":
106
113
  return toCSV(allResults);
107
114
  case "html":
@@ -116,7 +123,9 @@ function toCSV(allResults) {
116
123
  if (result) {
117
124
  result.violations.forEach((v) => {
118
125
  v.nodes.forEach((n) => {
119
- rows.push(escapeCSV(url) + "," + escapeCSV(v.id) + "," + escapeCSV(v.impact) + "," + escapeCSV(v.description) + "," + escapeCSV(Array.isArray(n.target) ? n.target.join("; ") : String(n.target)) + "," + escapeCSV(n.failureSummary ?? ""));
126
+ rows.push(
127
+ escapeCSV(url) + "," + escapeCSV(v.id) + "," + escapeCSV(v.impact) + "," + escapeCSV(v.description) + "," + escapeCSV(Array.isArray(n.target) ? n.target.join("; ") : String(n.target)) + "," + escapeCSV(n.failureSummary ?? "")
128
+ );
120
129
  });
121
130
  });
122
131
  }
@@ -136,8 +145,7 @@ function toHTML(allResults) {
136
145
  impactCounts: /* @__PURE__ */ new Map()
137
146
  };
138
147
  allResults.forEach(({ result }) => {
139
- if (!result)
140
- return;
148
+ if (!result) return;
141
149
  summary.pagesAudited++;
142
150
  const pageViolations = result.violations.reduce((acc, v) => {
143
151
  const nodesCount = (v.nodes || []).length;
@@ -150,13 +158,11 @@ function toHTML(allResults) {
150
158
  }
151
159
  return acc;
152
160
  }, 0);
153
- if (pageViolations > 0)
154
- summary.pagesWithViolations++;
161
+ if (pageViolations > 0) summary.pagesWithViolations++;
155
162
  });
156
163
  const rows = [];
157
164
  allResults.forEach(({ url, result }) => {
158
- if (!result)
159
- return;
165
+ if (!result) return;
160
166
  result.violations.forEach((v) => {
161
167
  v.nodes.forEach((n) => {
162
168
  const target = Array.isArray(n.target) ? n.target.join("; ") : String(n.target);
@@ -262,7 +268,7 @@ function escapeClass(s) {
262
268
  return String(s ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-");
263
269
  }
264
270
  var init_formatters = __esm({
265
- "src/utils/audit/src/formatters/formatters.js"() {
271
+ "src/utils/audit/src/formatters/formatters.ts"() {
266
272
  "use strict";
267
273
  }
268
274
  });
@@ -275,6 +281,10 @@ var init_contract = __esm({
275
281
  menu: {
276
282
  path: "./contracts/MenuContract.json",
277
283
  component: "menu"
284
+ },
285
+ combobox: {
286
+ path: "./contracts/ComboboxContract.json",
287
+ component: "combobox"
278
288
  }
279
289
  };
280
290
  }
@@ -13018,7 +13028,12 @@ async function runContractTests(componentName, component) {
13018
13028
  const skipped = [];
13019
13029
  for (const test of componentContract.static[0].assertions) {
13020
13030
  if (test.target !== "relative") {
13021
- const target = component.querySelector(componentContract.selectors[test.target]);
13031
+ const selector = componentContract.selectors[test.target];
13032
+ if (!selector) {
13033
+ failures.push(`Selector for target ${test.target} not found.`);
13034
+ continue;
13035
+ }
13036
+ const target = component.querySelector(selector);
13022
13037
  if (!target) {
13023
13038
  failures.push(`Target ${test.target} not found.`);
13024
13039
  continue;
@@ -13076,13 +13091,17 @@ async function runContractTests(componentName, component) {
13076
13091
  }
13077
13092
  const { action, assertions } = dynamicTest;
13078
13093
  const failuresBeforeTest = failures.length;
13079
- const containerElement = component.querySelector(componentContract.selectors.container);
13080
- const triggerElement = component.querySelector(componentContract.selectors.trigger);
13081
- if (containerElement && triggerElement) {
13082
- const isContainerVisible = containerElement.style.display !== "none";
13083
- if (isContainerVisible) {
13084
- fireEvent.click(triggerElement);
13085
- await new Promise((resolve) => setTimeout(resolve, 50));
13094
+ const containerSelector = componentContract.selectors.container;
13095
+ const triggerSelector = componentContract.selectors.trigger;
13096
+ if (containerSelector && triggerSelector) {
13097
+ const containerElement = component.querySelector(containerSelector);
13098
+ const triggerElement = component.querySelector(triggerSelector);
13099
+ if (containerElement && triggerElement) {
13100
+ const isContainerVisible = containerElement.style.display !== "none";
13101
+ if (isContainerVisible) {
13102
+ fireEvent.click(triggerElement);
13103
+ await new Promise((resolve) => setTimeout(resolve, 50));
13104
+ }
13086
13105
  }
13087
13106
  }
13088
13107
  const preActionExpectedTargets = /* @__PURE__ */ new Map();
@@ -13099,7 +13118,12 @@ async function runContractTests(componentName, component) {
13099
13118
  if (act.target === "document") {
13100
13119
  fireEvent.click(document.body);
13101
13120
  } else {
13102
- const target = component.querySelector(componentContract.selectors[act.target]);
13121
+ const selector = componentContract.selectors[act.target];
13122
+ if (!selector) {
13123
+ failures.push(`Selector for action target ${act.target} not found.`);
13124
+ continue;
13125
+ }
13126
+ const target = component.querySelector(selector);
13103
13127
  if (target instanceof HTMLElement) {
13104
13128
  target.focus();
13105
13129
  fireEvent.click(target);
@@ -13113,16 +13137,27 @@ async function runContractTests(componentName, component) {
13113
13137
  let target;
13114
13138
  if (act.target === "focusable" && ["Arrow Up", "Arrow Down", "Arrow Left", "Arrow Right", "Escape"].includes(act.key || "")) {
13115
13139
  const activeElement = document.activeElement;
13116
- const containerElement2 = component.querySelector(componentContract.selectors.container);
13117
- const focusableItems = containerElement2?.querySelectorAll(componentContract.selectors.focusable);
13140
+ const containerSelector2 = componentContract.selectors.container;
13141
+ const focusableSelector = componentContract.selectors.focusable;
13142
+ if (!containerSelector2 || !focusableSelector) {
13143
+ failures.push(`Container or focusable selector not found.`);
13144
+ continue;
13145
+ }
13146
+ const containerElement = component.querySelector(containerSelector2);
13147
+ const focusableItems = containerElement?.querySelectorAll(focusableSelector);
13118
13148
  if (focusableItems && focusableItems.length > 0) {
13119
13149
  const focusedItem = Array.from(focusableItems).find((item) => item === activeElement);
13120
13150
  target = focusedItem || focusableItems[0];
13121
13151
  } else {
13122
- target = containerElement2;
13152
+ target = containerElement;
13123
13153
  }
13124
13154
  } else {
13125
- target = component.querySelector(componentContract.selectors[act.target]);
13155
+ const selector = componentContract.selectors[act.target];
13156
+ if (!selector) {
13157
+ failures.push(`Selector for keypress target ${act.target} not found.`);
13158
+ continue;
13159
+ }
13160
+ target = component.querySelector(selector);
13126
13161
  }
13127
13162
  if (target) {
13128
13163
  target.focus();
@@ -13164,7 +13199,12 @@ async function runContractTests(componentName, component) {
13164
13199
  }
13165
13200
  target = resolveRelativeTarget(component, relativeSelector, assertion.expectedValue);
13166
13201
  } else {
13167
- target = component.querySelector(componentContract.selectors[assertion.target]);
13202
+ const selector = componentContract.selectors[assertion.target];
13203
+ if (!selector) {
13204
+ failures.push(`Selector for assertion target ${assertion.target} not found.`);
13205
+ continue;
13206
+ }
13207
+ target = component.querySelector(selector);
13168
13208
  }
13169
13209
  if (!target) {
13170
13210
  failures.push(`Target ${assertion.target} not found.`);
@@ -13262,7 +13302,11 @@ async function runContractTestsPlaywright(componentName, url) {
13262
13302
  waitUntil: "domcontentloaded",
13263
13303
  timeout: 6e4
13264
13304
  });
13265
- await page.waitForSelector(componentContract.selectors.trigger, { timeout: 6e4 });
13305
+ const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
13306
+ if (!mainSelector) {
13307
+ throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
13308
+ }
13309
+ await page.waitForSelector(mainSelector, { timeout: 6e4 });
13266
13310
  async function resolveRelativeTarget(selector, relative) {
13267
13311
  const items = await page.locator(selector).all();
13268
13312
  switch (relative) {
@@ -13333,17 +13377,61 @@ async function runContractTestsPlaywright(componentName, url) {
13333
13377
  for (const dynamicTest of componentContract.dynamic || []) {
13334
13378
  const { action, assertions } = dynamicTest;
13335
13379
  const failuresBeforeTest = failures.length;
13336
- const containerElement = page.locator(componentContract.selectors.container).first();
13337
- const triggerElement = page.locator(componentContract.selectors.trigger).first();
13338
- const isContainerVisible = await containerElement.isVisible();
13339
- if (isContainerVisible) {
13340
- await triggerElement.click();
13341
- await page.waitForTimeout(50);
13380
+ if (componentContract.selectors.listbox || componentContract.selectors.container) {
13381
+ const popupSelector = componentContract.selectors.listbox || componentContract.selectors.container;
13382
+ if (!popupSelector) continue;
13383
+ const popupElement = page.locator(popupSelector).first();
13384
+ const isPopupVisible = await popupElement.isVisible();
13385
+ if (isPopupVisible) {
13386
+ const closeSelector = componentContract.selectors.input || componentContract.selectors.trigger;
13387
+ if (closeSelector) {
13388
+ const closeElement = page.locator(closeSelector).first();
13389
+ await closeElement.focus();
13390
+ await page.keyboard.press("Escape");
13391
+ await page.waitForTimeout(200);
13392
+ if (componentContract.selectors.input) {
13393
+ const inputElement = page.locator(componentContract.selectors.input).first();
13394
+ await inputElement.clear();
13395
+ await page.waitForTimeout(50);
13396
+ }
13397
+ }
13398
+ }
13342
13399
  }
13343
13400
  for (const act of action) {
13401
+ if (act.type === "focus") {
13402
+ const focusSelector = componentContract.selectors[act.target];
13403
+ if (!focusSelector) {
13404
+ failures.push(`Selector for focus target ${act.target} not found.`);
13405
+ continue;
13406
+ }
13407
+ await page.locator(focusSelector).first().focus();
13408
+ await page.waitForTimeout(50);
13409
+ }
13410
+ if (act.type === "type" && act.value) {
13411
+ const typeSelector = componentContract.selectors[act.target];
13412
+ if (!typeSelector) {
13413
+ failures.push(`Selector for type target ${act.target} not found.`);
13414
+ continue;
13415
+ }
13416
+ await page.locator(typeSelector).first().fill(act.value);
13417
+ await page.waitForTimeout(50);
13418
+ }
13344
13419
  if (act.type === "click") {
13345
13420
  if (act.target === "document") {
13346
13421
  await page.mouse.click(10, 10);
13422
+ } else if (act.target === "relative" && act.relativeTarget) {
13423
+ const relativeSelector = componentContract.selectors.relative;
13424
+ if (!relativeSelector) {
13425
+ failures.push(`Relative selector not defined for click action.`);
13426
+ continue;
13427
+ }
13428
+ const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
13429
+ if (!relativeElement) {
13430
+ failures.push(`Could not resolve relative target ${act.relativeTarget} for click.`);
13431
+ continue;
13432
+ }
13433
+ await relativeElement.click();
13434
+ await page.waitForTimeout(200);
13347
13435
  } else {
13348
13436
  const actionSelector = componentContract.selectors[act.target];
13349
13437
  if (!actionSelector) {
@@ -13392,6 +13480,30 @@ async function runContractTestsPlaywright(componentName, url) {
13392
13480
  await target.press(keyValue);
13393
13481
  }
13394
13482
  }
13483
+ if (act.type === "hover") {
13484
+ if (act.target === "relative" && act.relativeTarget) {
13485
+ const relativeSelector = componentContract.selectors.relative;
13486
+ if (!relativeSelector) {
13487
+ failures.push(`Relative selector not defined for hover action.`);
13488
+ continue;
13489
+ }
13490
+ const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
13491
+ if (!relativeElement) {
13492
+ failures.push(`Could not resolve relative target ${act.relativeTarget} for hover.`);
13493
+ continue;
13494
+ }
13495
+ await relativeElement.hover();
13496
+ await page.waitForTimeout(50);
13497
+ } else {
13498
+ const hoverSelector = componentContract.selectors[act.target];
13499
+ if (!hoverSelector) {
13500
+ failures.push(`Selector for hover target ${act.target} not found.`);
13501
+ continue;
13502
+ }
13503
+ await page.locator(hoverSelector).first().hover();
13504
+ await page.waitForTimeout(50);
13505
+ }
13506
+ }
13395
13507
  await page.waitForTimeout(100);
13396
13508
  }
13397
13509
  for (const assertion of assertions) {
@@ -13402,11 +13514,12 @@ async function runContractTestsPlaywright(componentName, url) {
13402
13514
  failures.push("Relative selector is not defined in the contract.");
13403
13515
  continue;
13404
13516
  }
13405
- if (!assertion.expectedValue) {
13406
- failures.push("Expected value for relative target is not defined.");
13517
+ const relativeTargetValue = assertion.relativeTarget || assertion.expectedValue;
13518
+ if (!relativeTargetValue) {
13519
+ failures.push("Relative target or expected value is not defined.");
13407
13520
  continue;
13408
13521
  }
13409
- target = await resolveRelativeTarget(relativeSelector, assertion.expectedValue);
13522
+ target = await resolveRelativeTarget(relativeSelector, relativeTargetValue);
13410
13523
  } else {
13411
13524
  const assertionSelector = componentContract.selectors[assertion.target];
13412
13525
  if (!assertionSelector) {
@@ -13437,12 +13550,38 @@ async function runContractTestsPlaywright(componentName, url) {
13437
13550
  }
13438
13551
  if (assertion.assertion === "toHaveAttribute" && assertion.attribute && assertion.expectedValue) {
13439
13552
  const attributeValue = await target.getAttribute(assertion.attribute);
13440
- if (attributeValue === assertion.expectedValue) {
13553
+ if (assertion.expectedValue === "!empty") {
13554
+ if (attributeValue && attributeValue.trim() !== "") {
13555
+ passes.push(`${assertion.target} has non-empty "${assertion.attribute}". Test: "${dynamicTest.description}".`);
13556
+ } else {
13557
+ failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should not be empty, found "${attributeValue}".`);
13558
+ }
13559
+ } else if (attributeValue === assertion.expectedValue) {
13441
13560
  passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
13442
13561
  } else {
13443
13562
  failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should be "${assertion.expectedValue}", found "${attributeValue}".`);
13444
13563
  }
13445
13564
  }
13565
+ if (assertion.assertion === "toHaveValue") {
13566
+ const inputValue = await target.inputValue().catch(() => "");
13567
+ if (assertion.expectedValue === "!empty") {
13568
+ if (inputValue && inputValue.trim() !== "") {
13569
+ passes.push(`${assertion.target} has non-empty value. Test: "${dynamicTest.description}".`);
13570
+ } else {
13571
+ failures.push(assertion.failureMessage + ` ${assertion.target} value should not be empty, found "${inputValue}".`);
13572
+ }
13573
+ } else if (assertion.expectedValue === "") {
13574
+ if (inputValue === "") {
13575
+ passes.push(`${assertion.target} has empty value. Test: "${dynamicTest.description}".`);
13576
+ } else {
13577
+ failures.push(assertion.failureMessage + ` ${assertion.target} value should be empty, found "${inputValue}".`);
13578
+ }
13579
+ } else if (inputValue === assertion.expectedValue) {
13580
+ passes.push(`${assertion.target} has expected value. Test: "${dynamicTest.description}".`);
13581
+ } else {
13582
+ failures.push(assertion.failureMessage + ` ${assertion.target} value should be "${assertion.expectedValue}", found "${inputValue}".`);
13583
+ }
13584
+ }
13446
13585
  if (assertion.assertion === "toHaveFocus") {
13447
13586
  const hasFocus = await target.evaluate((el) => el === document.activeElement);
13448
13587
  if (hasFocus) {
@@ -13531,11 +13670,19 @@ async function testUiComponent(componentName, component, url) {
13531
13670
  }
13532
13671
  if (results.violations.length > 0) {
13533
13672
  const violationCount = results.violations.length;
13673
+ const violationDetails = results.violations.map(
13674
+ (v) => `
13675
+ - ${v.id}: ${v.description}
13676
+ Impact: ${v.impact}
13677
+ Affected elements: ${v.nodes.length}
13678
+ Help: ${v.helpUrl}`
13679
+ ).join("\n");
13534
13680
  throw new Error(
13535
13681
  `
13536
13682
  \u274C ${violationCount} axe accessibility violation${violationCount > 1 ? "s" : ""} detected
13683
+ ${violationDetails}
13537
13684
 
13538
- \u{1F4CB} Check result.violations for details`
13685
+ \u{1F4CB} Full details available in result.violations`
13539
13686
  );
13540
13687
  }
13541
13688
  return result;
@@ -13573,14 +13720,14 @@ var init_test = __esm({
13573
13720
  }
13574
13721
  });
13575
13722
 
13576
- // src/utils/test/index.js
13723
+ // src/utils/test/index.ts
13577
13724
  var test_exports = {};
13578
13725
  __export(test_exports, {
13579
13726
  runTest: () => runTest,
13580
13727
  testUiComponent: () => testUiComponent
13581
13728
  });
13582
13729
  var init_test2 = __esm({
13583
- "src/utils/test/index.js"() {
13730
+ "src/utils/test/index.ts"() {
13584
13731
  "use strict";
13585
13732
  init_test();
13586
13733
  }
@@ -13592,7 +13739,7 @@ var import_chalk = __toESM(require("chalk"), 1);
13592
13739
  var import_path2 = __toESM(require("path"), 1);
13593
13740
  var import_fs_extra2 = __toESM(require("fs-extra"), 1);
13594
13741
 
13595
- // src/utils/cli/configLoader.js
13742
+ // src/utils/cli/configLoader.ts
13596
13743
  var import_path = __toESM(require("path"), 1);
13597
13744
  var import_fs_extra = __toESM(require("fs-extra"), 1);
13598
13745
  function validateConfig(config2) {
package/bin/cli.js CHANGED
@@ -7,7 +7,7 @@ import chalk from "chalk";
7
7
  import path2 from "path";
8
8
  import fs2 from "fs-extra";
9
9
 
10
- // src/utils/cli/configLoader.js
10
+ // src/utils/cli/configLoader.ts
11
11
  import path from "path";
12
12
  import fs from "fs-extra";
13
13
  function validateConfig(config) {
@@ -128,8 +128,8 @@ var program = new Command();
128
128
  program.name("aria-ease").description("Run accessibility tests and audits").version("2.2.3");
129
129
  program.command("audit").description("Run axe-core powered accessibility audit on webpages").option("-u, --url <url>", "Single URL to audit").option("-f, --format <format>", "Output format for the audit report: json | csv | html | all", "all").option("-o, --out <path>", "Directory to save the audit report", "./accessibility-reports/audit").action(async (opts) => {
130
130
  console.log(chalk.cyanBright("\u{1F680} Starting accessibility audit...\n"));
131
- const { runAudit } = await import("./audit-XABLAI36.js");
132
- const { formatResults } = await import("./formatters-2RPHPXW2.js");
131
+ const { runAudit } = await import("./audit-XZJXMUPL.js");
132
+ const { formatResults } = await import("./formatters-U4E5EVPL.js");
133
133
  const { config, configPath, errors } = await loadConfig(process.cwd());
134
134
  if (configPath) {
135
135
  console.log(chalk.green(`\u2705 Loaded config from ${path2.basename(configPath)}
@@ -204,7 +204,7 @@ program.command("audit").description("Run axe-core powered accessibility audit o
204
204
  console.log(chalk.green("\n\u{1F389} All audits completed."));
205
205
  });
206
206
  program.command("test").description("Run core a11y accessibility standard tests on UI components").action(async () => {
207
- const { runTest } = await import("./test-S2U633GD.js");
207
+ const { runTest } = await import("./test-PK5MBHIN.js");
208
208
  runTest();
209
209
  });
210
210
  program.command("help").description("Display help information").action(() => {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ContractReporter,
3
3
  contract_default
4
- } from "./chunk-JGKPHTSR.js";
4
+ } from "./chunk-5Z7PR3VC.js";
5
5
  import "./chunk-JSBRDJBE.js";
6
6
 
7
7
  // src/utils/test/contract/contractTestRunnerPlaywright.ts
@@ -30,7 +30,11 @@ async function runContractTestsPlaywright(componentName, url) {
30
30
  waitUntil: "domcontentloaded",
31
31
  timeout: 6e4
32
32
  });
33
- await page.waitForSelector(componentContract.selectors.trigger, { timeout: 6e4 });
33
+ const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
34
+ if (!mainSelector) {
35
+ throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
36
+ }
37
+ await page.waitForSelector(mainSelector, { timeout: 6e4 });
34
38
  async function resolveRelativeTarget(selector, relative) {
35
39
  const items = await page.locator(selector).all();
36
40
  switch (relative) {
@@ -101,17 +105,61 @@ async function runContractTestsPlaywright(componentName, url) {
101
105
  for (const dynamicTest of componentContract.dynamic || []) {
102
106
  const { action, assertions } = dynamicTest;
103
107
  const failuresBeforeTest = failures.length;
104
- const containerElement = page.locator(componentContract.selectors.container).first();
105
- const triggerElement = page.locator(componentContract.selectors.trigger).first();
106
- const isContainerVisible = await containerElement.isVisible();
107
- if (isContainerVisible) {
108
- await triggerElement.click();
109
- await page.waitForTimeout(50);
108
+ if (componentContract.selectors.listbox || componentContract.selectors.container) {
109
+ const popupSelector = componentContract.selectors.listbox || componentContract.selectors.container;
110
+ if (!popupSelector) continue;
111
+ const popupElement = page.locator(popupSelector).first();
112
+ const isPopupVisible = await popupElement.isVisible();
113
+ if (isPopupVisible) {
114
+ const closeSelector = componentContract.selectors.input || componentContract.selectors.trigger;
115
+ if (closeSelector) {
116
+ const closeElement = page.locator(closeSelector).first();
117
+ await closeElement.focus();
118
+ await page.keyboard.press("Escape");
119
+ await page.waitForTimeout(200);
120
+ if (componentContract.selectors.input) {
121
+ const inputElement = page.locator(componentContract.selectors.input).first();
122
+ await inputElement.clear();
123
+ await page.waitForTimeout(50);
124
+ }
125
+ }
126
+ }
110
127
  }
111
128
  for (const act of action) {
129
+ if (act.type === "focus") {
130
+ const focusSelector = componentContract.selectors[act.target];
131
+ if (!focusSelector) {
132
+ failures.push(`Selector for focus target ${act.target} not found.`);
133
+ continue;
134
+ }
135
+ await page.locator(focusSelector).first().focus();
136
+ await page.waitForTimeout(50);
137
+ }
138
+ if (act.type === "type" && act.value) {
139
+ const typeSelector = componentContract.selectors[act.target];
140
+ if (!typeSelector) {
141
+ failures.push(`Selector for type target ${act.target} not found.`);
142
+ continue;
143
+ }
144
+ await page.locator(typeSelector).first().fill(act.value);
145
+ await page.waitForTimeout(50);
146
+ }
112
147
  if (act.type === "click") {
113
148
  if (act.target === "document") {
114
149
  await page.mouse.click(10, 10);
150
+ } else if (act.target === "relative" && act.relativeTarget) {
151
+ const relativeSelector = componentContract.selectors.relative;
152
+ if (!relativeSelector) {
153
+ failures.push(`Relative selector not defined for click action.`);
154
+ continue;
155
+ }
156
+ const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
157
+ if (!relativeElement) {
158
+ failures.push(`Could not resolve relative target ${act.relativeTarget} for click.`);
159
+ continue;
160
+ }
161
+ await relativeElement.click();
162
+ await page.waitForTimeout(200);
115
163
  } else {
116
164
  const actionSelector = componentContract.selectors[act.target];
117
165
  if (!actionSelector) {
@@ -160,6 +208,30 @@ async function runContractTestsPlaywright(componentName, url) {
160
208
  await target.press(keyValue);
161
209
  }
162
210
  }
211
+ if (act.type === "hover") {
212
+ if (act.target === "relative" && act.relativeTarget) {
213
+ const relativeSelector = componentContract.selectors.relative;
214
+ if (!relativeSelector) {
215
+ failures.push(`Relative selector not defined for hover action.`);
216
+ continue;
217
+ }
218
+ const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
219
+ if (!relativeElement) {
220
+ failures.push(`Could not resolve relative target ${act.relativeTarget} for hover.`);
221
+ continue;
222
+ }
223
+ await relativeElement.hover();
224
+ await page.waitForTimeout(50);
225
+ } else {
226
+ const hoverSelector = componentContract.selectors[act.target];
227
+ if (!hoverSelector) {
228
+ failures.push(`Selector for hover target ${act.target} not found.`);
229
+ continue;
230
+ }
231
+ await page.locator(hoverSelector).first().hover();
232
+ await page.waitForTimeout(50);
233
+ }
234
+ }
163
235
  await page.waitForTimeout(100);
164
236
  }
165
237
  for (const assertion of assertions) {
@@ -170,11 +242,12 @@ async function runContractTestsPlaywright(componentName, url) {
170
242
  failures.push("Relative selector is not defined in the contract.");
171
243
  continue;
172
244
  }
173
- if (!assertion.expectedValue) {
174
- failures.push("Expected value for relative target is not defined.");
245
+ const relativeTargetValue = assertion.relativeTarget || assertion.expectedValue;
246
+ if (!relativeTargetValue) {
247
+ failures.push("Relative target or expected value is not defined.");
175
248
  continue;
176
249
  }
177
- target = await resolveRelativeTarget(relativeSelector, assertion.expectedValue);
250
+ target = await resolveRelativeTarget(relativeSelector, relativeTargetValue);
178
251
  } else {
179
252
  const assertionSelector = componentContract.selectors[assertion.target];
180
253
  if (!assertionSelector) {
@@ -205,12 +278,38 @@ async function runContractTestsPlaywright(componentName, url) {
205
278
  }
206
279
  if (assertion.assertion === "toHaveAttribute" && assertion.attribute && assertion.expectedValue) {
207
280
  const attributeValue = await target.getAttribute(assertion.attribute);
208
- if (attributeValue === assertion.expectedValue) {
281
+ if (assertion.expectedValue === "!empty") {
282
+ if (attributeValue && attributeValue.trim() !== "") {
283
+ passes.push(`${assertion.target} has non-empty "${assertion.attribute}". Test: "${dynamicTest.description}".`);
284
+ } else {
285
+ failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should not be empty, found "${attributeValue}".`);
286
+ }
287
+ } else if (attributeValue === assertion.expectedValue) {
209
288
  passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
210
289
  } else {
211
290
  failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should be "${assertion.expectedValue}", found "${attributeValue}".`);
212
291
  }
213
292
  }
293
+ if (assertion.assertion === "toHaveValue") {
294
+ const inputValue = await target.inputValue().catch(() => "");
295
+ if (assertion.expectedValue === "!empty") {
296
+ if (inputValue && inputValue.trim() !== "") {
297
+ passes.push(`${assertion.target} has non-empty value. Test: "${dynamicTest.description}".`);
298
+ } else {
299
+ failures.push(assertion.failureMessage + ` ${assertion.target} value should not be empty, found "${inputValue}".`);
300
+ }
301
+ } else if (assertion.expectedValue === "") {
302
+ if (inputValue === "") {
303
+ passes.push(`${assertion.target} has empty value. Test: "${dynamicTest.description}".`);
304
+ } else {
305
+ failures.push(assertion.failureMessage + ` ${assertion.target} value should be empty, found "${inputValue}".`);
306
+ }
307
+ } else if (inputValue === assertion.expectedValue) {
308
+ passes.push(`${assertion.target} has expected value. Test: "${dynamicTest.description}".`);
309
+ } else {
310
+ failures.push(assertion.failureMessage + ` ${assertion.target} value should be "${assertion.expectedValue}", found "${inputValue}".`);
311
+ }
312
+ }
214
313
  if (assertion.assertion === "toHaveFocus") {
215
314
  const hasFocus = await target.evaluate((el) => el === document.activeElement);
216
315
  if (hasFocus) {