aria-ease 6.12.0 → 6.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +2 -2
  2. package/dist/{ComboboxComponentStrategy-OGRVZXAF.js → ComboboxComponentStrategy-DU342VMB.js} +7 -7
  3. package/dist/RelativeTargetResolver-DJAITO6D.js +7 -0
  4. package/dist/{audit-RM6TCZ5C.js → audit-JYEPKLHR.js} +5 -0
  5. package/dist/{chunk-FZ7GMIJB.js → chunk-4DU5Z5BR.js} +0 -2
  6. package/dist/chunk-GLT43UVH.js +43 -0
  7. package/dist/cli.cjs +138 -28
  8. package/dist/cli.js +3 -3
  9. package/dist/{contractTestRunnerPlaywright-EWAWQVHT.js → contractTestRunnerPlaywright-47DCBO4A.js} +126 -60
  10. package/dist/{contractTestRunnerPlaywright-DIXP5DQ3.js → contractTestRunnerPlaywright-UJKXRXBS.js} +126 -60
  11. package/dist/index.cjs +256 -53
  12. package/dist/index.d.cts +1 -1
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.js +126 -28
  15. package/dist/src/combobox/index.cjs +4 -0
  16. package/dist/src/combobox/index.js +4 -0
  17. package/dist/src/utils/test/{ComboboxComponentStrategy-5AECQSRN.js → ComboboxComponentStrategy-XKQ72RFD.js} +7 -7
  18. package/dist/src/utils/test/RelativeTargetResolver-G2XDN2VV.js +1 -0
  19. package/dist/src/utils/test/{chunk-FZ7GMIJB.js → chunk-4DU5Z5BR.js} +0 -2
  20. package/dist/src/utils/test/chunk-GLT43UVH.js +41 -0
  21. package/dist/src/utils/test/{contractTestRunnerPlaywright-CIZOXYRW.js → contractTestRunnerPlaywright-AZ4QKLYT.js} +124 -60
  22. package/dist/src/utils/test/dsl/index.cjs +119 -25
  23. package/dist/src/utils/test/dsl/index.d.cts +1 -1
  24. package/dist/src/utils/test/dsl/index.d.ts +1 -1
  25. package/dist/src/utils/test/dsl/index.js +119 -25
  26. package/dist/src/utils/test/index.cjs +133 -28
  27. package/dist/src/utils/test/index.js +3 -3
  28. package/dist/{test-HBPCSYH5.js → test-6Y4CIQOM.js} +3 -3
  29. package/package.json +2 -2
package/README.md CHANGED
@@ -1000,7 +1000,7 @@ export default {
1000
1000
  audit: {
1001
1001
  urls: [
1002
1002
  "http://localhost:5173", // Homepage
1003
- "http://localhost:5173/docs", // Docs
1003
+ "http://localhost:5173/getting-started", // Docs
1004
1004
  "http://localhost:5173/examples", // Examples
1005
1005
  ],
1006
1006
  output: {
@@ -1130,7 +1130,7 @@ You've shifted accessibility left (into development), automated the verification
1130
1130
 
1131
1131
  ## 📖 More Resources
1132
1132
 
1133
- - [Full Documentation](https://ariaease.site/docs)
1133
+ - [Full Documentation](https://ariaease.site/getting-started)
1134
1134
  - [GitHub Repository](https://github.com/aria-ease/aria-ease)
1135
1135
  - [Report Issues](https://github.com/aria-ease/aria-ease/issues)
1136
1136
  - [Contributing Guide](https://github.com/aria-ease/aria-ease/blob/main/CONTRIBUTION-GUIDELINES.md)
@@ -17,7 +17,7 @@ var ComboboxComponentStrategy = class {
17
17
  const popupElement = page.locator(popupSelector).first();
18
18
  const isPopupVisible = await popupElement.isVisible().catch(() => false);
19
19
  if (!isPopupVisible) return;
20
- let listBoxClosed = false;
20
+ let popupClosed = false;
21
21
  let closeSelector = this.selectors.input;
22
22
  if (!closeSelector && this.selectors.focusable) {
23
23
  closeSelector = this.selectors.focusable;
@@ -28,18 +28,18 @@ var ComboboxComponentStrategy = class {
28
28
  const closeElement = page.locator(closeSelector).first();
29
29
  await closeElement.focus();
30
30
  await page.keyboard.press("Escape");
31
- listBoxClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
31
+ popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
32
32
  }
33
- if (!listBoxClosed && this.selectors.button) {
33
+ if (!popupClosed && this.selectors.button) {
34
34
  const buttonElement = page.locator(this.selectors.button).first();
35
35
  await buttonElement.click({ timeout: this.actionTimeoutMs });
36
- listBoxClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
36
+ popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
37
37
  }
38
- if (!listBoxClosed) {
38
+ if (!popupClosed) {
39
39
  await page.mouse.click(10, 10);
40
- listBoxClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
40
+ popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
41
41
  }
42
- if (!listBoxClosed) {
42
+ if (!popupClosed) {
43
43
  throw new Error(
44
44
  `\u274C FATAL: Cannot close combobox popup between tests. Popup remains visible after trying:
45
45
  1. Escape key
@@ -0,0 +1,7 @@
1
+ import {
2
+ RelativeTargetResolver
3
+ } from "./chunk-GLT43UVH.js";
4
+ import "./chunk-I2KLQ2HA.js";
5
+ export {
6
+ RelativeTargetResolver
7
+ };
@@ -19,6 +19,11 @@ async function runAudit(url, options) {
19
19
  const context = await browser.newContext();
20
20
  const page = await context.newPage();
21
21
  await page.goto(url, { waitUntil, timeout });
22
+ try {
23
+ await page.waitForSelector("main", { state: "visible", timeout });
24
+ } catch (waitError) {
25
+ console.warn(`\u26A0\uFE0F Warning: <main> landmark not found or not visible on ${url} after ${timeout}ms. Audit will continue, but results may be inaccurate. Consider adding a <main> element to improve audit accuracy. ${waitError instanceof Error ? waitError.message : String(waitError)}`);
26
+ }
22
27
  const axe = new AxeBuilder({ page });
23
28
  const axeResults = await axe.analyze();
24
29
  await page.close();
@@ -309,9 +309,7 @@ async function getOrCreateContext() {
309
309
  if (!sharedContext) {
310
310
  const browser = await getOrCreateBrowser();
311
311
  sharedContext = await browser.newContext({
312
- // Isolated context - no permissions, no geolocation, etc.
313
312
  permissions: [],
314
- // Ignore HTTPS errors for local dev servers
315
313
  ignoreHTTPSErrors: true
316
314
  });
317
315
  }
@@ -0,0 +1,43 @@
1
+ // src/utils/test/src/RelativeTargetResolver.ts
2
+ var RelativeTargetResolver = class {
3
+ /**
4
+ * Resolve a relative target like "first", "second", "last", "next", "previous"
5
+ * @param page Playwright page instance
6
+ * @param selector Base selector to find elements
7
+ * @param relative Relative position (first, second, last, next, previous)
8
+ * @returns The resolved Locator or null if not found
9
+ */
10
+ static async resolve(page, selector, relative) {
11
+ const items = await page.locator(selector).all();
12
+ switch (relative) {
13
+ case "first":
14
+ return items[0];
15
+ case "second":
16
+ return items[1];
17
+ case "last":
18
+ return items[items.length - 1];
19
+ case "next": {
20
+ const currentIndex = await page.evaluate(([sel]) => {
21
+ const items2 = Array.from(document.querySelectorAll(sel));
22
+ return items2.indexOf(document.activeElement);
23
+ }, [selector]);
24
+ const nextIndex = (currentIndex + 1) % items.length;
25
+ return items[nextIndex];
26
+ }
27
+ case "previous": {
28
+ const currentIndex = await page.evaluate(([sel]) => {
29
+ const items2 = Array.from(document.querySelectorAll(sel));
30
+ return items2.indexOf(document.activeElement);
31
+ }, [selector]);
32
+ const prevIndex = (currentIndex - 1 + items.length) % items.length;
33
+ return items[prevIndex];
34
+ }
35
+ default:
36
+ return null;
37
+ }
38
+ }
39
+ };
40
+
41
+ export {
42
+ RelativeTargetResolver
43
+ };
package/dist/cli.cjs CHANGED
@@ -356,6 +356,11 @@ async function runAudit(url, options) {
356
356
  const context = await browser.newContext();
357
357
  const page = await context.newPage();
358
358
  await page.goto(url, { waitUntil, timeout });
359
+ try {
360
+ await page.waitForSelector("main", { state: "visible", timeout });
361
+ } catch (waitError) {
362
+ console.warn(`\u26A0\uFE0F Warning: <main> landmark not found or not visible on ${url} after ${timeout}ms. Audit will continue, but results may be inaccurate. Consider adding a <main> element to improve audit accuracy. ${waitError instanceof Error ? waitError.message : String(waitError)}`);
363
+ }
359
364
  const axe2 = new import_playwright.default({ page });
360
365
  const axeResults = await axe2.analyze();
361
366
  await page.close();
@@ -1030,7 +1035,7 @@ async function runContractTests(contractPath, componentName, component, strictne
1030
1035
  staticPassed += 1;
1031
1036
  reporter.reportStaticTest(`${test.target} has ${test.attribute}`, "pass", void 0, staticLevel);
1032
1037
  }
1033
- } else if (!attributeValue || !test.expectedValue.split(" | ").includes(attributeValue)) {
1038
+ } else if (!attributeValue || typeof test.expectedValue === "string" && !test.expectedValue.split(" | ").includes(attributeValue)) {
1034
1039
  const outcome = classifyFailure(test.failureMessage + ` Attribute value does not match expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`, test.level);
1035
1040
  if (outcome.status === "fail") staticFailed += 1;
1036
1041
  if (outcome.status === "warn") staticWarnings += 1;
@@ -1078,9 +1083,7 @@ async function getOrCreateContext() {
1078
1083
  if (!sharedContext) {
1079
1084
  const browser = await getOrCreateBrowser();
1080
1085
  sharedContext = await browser.newContext({
1081
- // Isolated context - no permissions, no geolocation, etc.
1082
1086
  permissions: [],
1083
- // Ignore HTTPS errors for local dev servers
1084
1087
  ignoreHTTPSErrors: true
1085
1088
  });
1086
1089
  }
@@ -1278,7 +1281,7 @@ var init_ComboboxComponentStrategy = __esm({
1278
1281
  const popupElement = page.locator(popupSelector).first();
1279
1282
  const isPopupVisible = await popupElement.isVisible().catch(() => false);
1280
1283
  if (!isPopupVisible) return;
1281
- let listBoxClosed = false;
1284
+ let popupClosed = false;
1282
1285
  let closeSelector = this.selectors.input;
1283
1286
  if (!closeSelector && this.selectors.focusable) {
1284
1287
  closeSelector = this.selectors.focusable;
@@ -1289,18 +1292,18 @@ var init_ComboboxComponentStrategy = __esm({
1289
1292
  const closeElement = page.locator(closeSelector).first();
1290
1293
  await closeElement.focus();
1291
1294
  await page.keyboard.press("Escape");
1292
- listBoxClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
1295
+ popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
1293
1296
  }
1294
- if (!listBoxClosed && this.selectors.button) {
1297
+ if (!popupClosed && this.selectors.button) {
1295
1298
  const buttonElement = page.locator(this.selectors.button).first();
1296
1299
  await buttonElement.click({ timeout: this.actionTimeoutMs });
1297
- listBoxClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
1300
+ popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
1298
1301
  }
1299
- if (!listBoxClosed) {
1302
+ if (!popupClosed) {
1300
1303
  await page.mouse.click(10, 10);
1301
- listBoxClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
1304
+ popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
1302
1305
  }
1303
- if (!listBoxClosed) {
1306
+ if (!popupClosed) {
1304
1307
  throw new Error(
1305
1308
  `\u274C FATAL: Cannot close combobox popup between tests. Popup remains visible after trying:
1306
1309
  1. Escape key
@@ -1520,6 +1523,10 @@ var init_ComponentDetector = __esm({
1520
1523
  });
1521
1524
 
1522
1525
  // src/utils/test/src/RelativeTargetResolver.ts
1526
+ var RelativeTargetResolver_exports = {};
1527
+ __export(RelativeTargetResolver_exports, {
1528
+ RelativeTargetResolver: () => RelativeTargetResolver
1529
+ });
1523
1530
  var RelativeTargetResolver;
1524
1531
  var init_RelativeTargetResolver = __esm({
1525
1532
  "src/utils/test/src/RelativeTargetResolver.ts"() {
@@ -1595,16 +1602,16 @@ var init_ActionExecutor = __esm({
1595
1602
  async focus(target, relativeTarget, virtualId) {
1596
1603
  try {
1597
1604
  if (target === "virtual" && virtualId) {
1598
- const inputSelector = this.selectors.input;
1599
- if (!inputSelector) {
1600
- return { success: false, error: `Input selector not defined for virtual focus.` };
1605
+ const mainSelector = this.selectors.main;
1606
+ if (!mainSelector) {
1607
+ return { success: false, error: `Main selector not defined for virtual focus.` };
1601
1608
  }
1602
- const input = this.page.locator(inputSelector).first();
1603
- const exists = await input.count();
1609
+ const main = this.page.locator(mainSelector).first();
1610
+ const exists = await main.count();
1604
1611
  if (!exists) {
1605
- return { success: false, error: `Input element not found for virtual focus.` };
1612
+ return { success: false, error: `Main element not found for virtual focus.` };
1606
1613
  }
1607
- await input.evaluate((el, id) => {
1614
+ await main.evaluate((el, id) => {
1608
1615
  el.setAttribute("aria-activedescendant", id);
1609
1616
  }, virtualId);
1610
1617
  return { success: true };
@@ -1906,6 +1913,10 @@ var init_AssertionRunner = __esm({
1906
1913
  };
1907
1914
  }
1908
1915
  }
1916
+ if (typeof expectedValue !== "string") {
1917
+ console.error("[AssertionRunner] expectedValue is not a string:", expectedValue);
1918
+ throw new Error(`AssertionRunner: expectedValue for attribute assertion must be a string, but got: ${JSON.stringify(expectedValue)}`);
1919
+ }
1909
1920
  const expectedValues = expectedValue.split(" | ").map((v) => v.trim());
1910
1921
  const attributeValue = await target.getAttribute(attribute);
1911
1922
  if (attributeValue !== null && expectedValues.includes(attributeValue)) {
@@ -1966,13 +1977,21 @@ var init_AssertionRunner = __esm({
1966
1977
  /**
1967
1978
  * Validate focus assertion
1968
1979
  */
1969
- async validateFocus(target, targetName, failureMessage, testDescription) {
1980
+ async validateFocus(target, targetName, expectedFocus, failureMessage, testDescription) {
1970
1981
  try {
1971
- await (0, test_exports.expect)(target).toBeFocused({ timeout: this.timeoutMs });
1972
- return {
1973
- success: true,
1974
- passMessage: `${targetName} has focus as expected. Test: "${testDescription}".`
1975
- };
1982
+ if (expectedFocus) {
1983
+ await (0, test_exports.expect)(target).toBeFocused({ timeout: this.timeoutMs });
1984
+ return {
1985
+ success: true,
1986
+ passMessage: `${targetName} has focus as expected. Test: "${testDescription}".`
1987
+ };
1988
+ } else {
1989
+ await (0, test_exports.expect)(target).not.toBeFocused({ timeout: this.timeoutMs });
1990
+ return {
1991
+ success: true,
1992
+ passMessage: `${targetName} does not have focus as expected. Test: "${testDescription}".`
1993
+ };
1994
+ }
1976
1995
  } catch {
1977
1996
  const actualFocus = await this.page.evaluate(() => {
1978
1997
  const focused = document.activeElement;
@@ -2058,7 +2077,9 @@ var init_AssertionRunner = __esm({
2058
2077
  }
2059
2078
  return { success: false, failMessage: "Missing expectedValue for toHaveValue assertion" };
2060
2079
  case "toHaveFocus":
2061
- return this.validateFocus(target, assertion.target, assertion.failureMessage || "", testDescription);
2080
+ return this.validateFocus(target, assertion.target, true, assertion.failureMessage || "", testDescription);
2081
+ case "notToHaveFocus":
2082
+ return this.validateFocus(target, assertion.target, false, assertion.failureMessage || "", testDescription);
2062
2083
  case "toHaveRole":
2063
2084
  if (assertion.expectedValue !== void 0) {
2064
2085
  return this.validateRole(target, assertion.target, assertion.expectedValue, assertion.failureMessage || "", testDescription);
@@ -2338,6 +2359,52 @@ This usually means:
2338
2359
  reporter.reportStaticTest(relDescription, "pass", void 0, relationshipLevel);
2339
2360
  }
2340
2361
  }
2362
+ async function resolveExpectedValue(expectedValue, selectors, page2, context = {}) {
2363
+ if (!expectedValue || typeof expectedValue !== "object" || !("ref" in expectedValue)) return expectedValue;
2364
+ let refSelector;
2365
+ if (expectedValue.ref === "relative") {
2366
+ if (!expectedValue.relativeTarget || !context.relativeBaseSelector) return void 0;
2367
+ const baseLocator = page2.locator(context.relativeBaseSelector);
2368
+ const count = await baseLocator.count();
2369
+ let idx = 0;
2370
+ if (expectedValue.relativeTarget === "first") idx = 0;
2371
+ else if (expectedValue.relativeTarget === "second") idx = 1;
2372
+ else if (expectedValue.relativeTarget === "last") idx = count - 1;
2373
+ else if (!isNaN(Number(expectedValue.relativeTarget))) idx = Number(expectedValue.relativeTarget);
2374
+ else idx = 0;
2375
+ if (idx < 0 || idx >= count) return void 0;
2376
+ const relElem = baseLocator.nth(idx);
2377
+ return await getPropertyFromLocator(relElem, expectedValue.property || expectedValue.attribute);
2378
+ } else {
2379
+ refSelector = selectors[expectedValue.ref];
2380
+ if (!refSelector) throw new Error(`Selector for ref '${expectedValue.ref}' not found in contract selectors.`);
2381
+ const refLocator = page2.locator(refSelector).first();
2382
+ return await getPropertyFromLocator(refLocator, expectedValue.property || expectedValue.attribute);
2383
+ }
2384
+ }
2385
+ async function getPropertyFromLocator(locator, property) {
2386
+ if (!locator) return void 0;
2387
+ if (!property || property === "id") {
2388
+ return await locator.getAttribute("id") ?? void 0;
2389
+ } else if (property === "class") {
2390
+ return await locator.getAttribute("class") ?? void 0;
2391
+ } else if (property === "textContent") {
2392
+ return await locator.evaluate((el) => el.textContent ?? void 0);
2393
+ } else if (property.startsWith("aria-")) {
2394
+ return await locator.getAttribute(property) ?? void 0;
2395
+ } else if (property.endsWith("*")) {
2396
+ const attrs = await locator.evaluate((el) => {
2397
+ const out = [];
2398
+ for (const attr of Array.from(el.attributes)) {
2399
+ if (attr.name.startsWith("aria-")) out.push(`${attr.name}=${attr.value}`);
2400
+ }
2401
+ return out.join(";");
2402
+ });
2403
+ return attrs;
2404
+ } else {
2405
+ return await locator.getAttribute(property) ?? void 0;
2406
+ }
2407
+ }
2341
2408
  const staticAssertionRunner = new AssertionRunner(page, componentContract.selectors, assertionTimeoutMs);
2342
2409
  for (const test of componentContract.static[0]?.assertions || []) {
2343
2410
  if (test.target === "relative") continue;
@@ -2380,6 +2447,22 @@ This usually means:
2380
2447
  }
2381
2448
  return false;
2382
2449
  };
2450
+ let expectedValue = test.expectedValue;
2451
+ if (test.expectedValue && typeof test.expectedValue === "object" && "ref" in test.expectedValue) {
2452
+ const context = {};
2453
+ const relTarget = test.relativeTarget;
2454
+ if (test.expectedValue.ref === "relative" && test.target === "relative" && relTarget) {
2455
+ const baseSel = componentContract.selectors[relTarget];
2456
+ if (!baseSel) throw new Error(`Selector for relativeTarget '${relTarget}' not found in contract selectors.`);
2457
+ context.relativeBaseSelector = baseSel;
2458
+ } else if (test.expectedValue.ref === "relative" && relTarget) {
2459
+ const baseSel = componentContract.selectors[relTarget];
2460
+ if (!baseSel) throw new Error(`Selector for relativeTarget '${relTarget}' not found in contract selectors.`);
2461
+ context.relativeBaseSelector = baseSel;
2462
+ }
2463
+ expectedValue = await resolveExpectedValue(test.expectedValue, componentContract.selectors, page, context);
2464
+ console.log("Expected value in static check", expectedValue);
2465
+ }
2383
2466
  if (!test.expectedValue) {
2384
2467
  const attributes = test.attribute.split(" | ");
2385
2468
  let hasAny = false;
@@ -2413,16 +2496,17 @@ This usually means:
2413
2496
  reporter.reportStaticTest(staticDescription, "pass", void 0, staticLevel);
2414
2497
  }
2415
2498
  } else {
2416
- if (isRedundantCheck(targetSelector, test.attribute, test.expectedValue)) {
2417
- passes.push(`${test.attribute}="${test.expectedValue}" on ${test.target} verified by selector (already present in: ${targetSelector}).`);
2499
+ if (isRedundantCheck(targetSelector, test.attribute, typeof expectedValue === "string" ? expectedValue : void 0)) {
2500
+ passes.push(`${test.attribute}="${expectedValue}" on ${test.target} verified by selector (already present in: ${targetSelector}).`);
2418
2501
  staticPassed += 1;
2419
2502
  reporter.reportStaticTest(staticDescription, "pass", void 0, staticLevel);
2420
2503
  } else {
2504
+ const valueToCheck = expectedValue ?? "";
2421
2505
  const result = await staticAssertionRunner.validateAttribute(
2422
2506
  target,
2423
2507
  test.target,
2424
2508
  test.attribute,
2425
- test.expectedValue,
2509
+ valueToCheck,
2426
2510
  test.failureMessage,
2427
2511
  "Static ARIA Test"
2428
2512
  );
@@ -2540,7 +2624,33 @@ This usually means:
2540
2624
  continue;
2541
2625
  }
2542
2626
  for (const assertion of assertions) {
2543
- const result = await assertionRunner.validate(assertion, dynamicTest.description);
2627
+ let expectedValue;
2628
+ if (assertion.expectedValue && typeof assertion.expectedValue === "object" && "ref" in assertion.expectedValue) {
2629
+ if (assertion.expectedValue.ref === "relative") {
2630
+ const { RelativeTargetResolver: RelativeTargetResolver2 } = await Promise.resolve().then(() => (init_RelativeTargetResolver(), RelativeTargetResolver_exports));
2631
+ const relativeSelector = componentContract.selectors.relative;
2632
+ if (!relativeSelector) throw new Error("Relative selector not defined in contract selectors.");
2633
+ const relTarget = assertion.relativeTarget || "first";
2634
+ const relElem = await RelativeTargetResolver2.resolve(page, relativeSelector, relTarget);
2635
+ if (!relElem) throw new Error(`Could not resolve relative target '${relTarget}' for expectedValue.`);
2636
+ const prop = assertion.expectedValue.property || assertion.expectedValue.attribute || "id";
2637
+ if (prop === "textContent") {
2638
+ expectedValue = await relElem.evaluate((el) => el.textContent ?? void 0);
2639
+ } else {
2640
+ const attr = await relElem.getAttribute(prop);
2641
+ expectedValue = attr === null ? void 0 : attr;
2642
+ }
2643
+ } else {
2644
+ expectedValue = await resolveExpectedValue(assertion.expectedValue, componentContract.selectors, page, {});
2645
+ }
2646
+ } else if (typeof assertion.expectedValue === "string" || typeof assertion.expectedValue === "undefined") {
2647
+ expectedValue = assertion.expectedValue;
2648
+ } else {
2649
+ expectedValue = "";
2650
+ }
2651
+ const assertionToRun = { ...assertion, expectedValue };
2652
+ const valueToCheck = expectedValue ?? "";
2653
+ const result = await assertionRunner.validate({ ...assertionToRun, expectedValue: valueToCheck }, dynamicTest.description);
2544
2654
  if (result.success && result.passMessage) {
2545
2655
  passes.push(result.passMessage);
2546
2656
  } else if (!result.success && result.failMessage) {
package/dist/cli.js CHANGED
@@ -17,7 +17,7 @@ var program = new Command();
17
17
  program.name("aria-ease").description("Run accessibility tests and audits").version("2.2.3");
18
18
  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) => {
19
19
  console.log(chalk.cyanBright("\u{1F680} Starting accessibility audit...\n"));
20
- const { runAudit } = await import("./audit-RM6TCZ5C.js");
20
+ const { runAudit } = await import("./audit-JYEPKLHR.js");
21
21
  const { formatResults } = await import("./formatters-32KQIIYS.js");
22
22
  const needsConfig = !opts.url;
23
23
  const { config, configPath, errors } = await loadConfig(process.cwd());
@@ -50,7 +50,7 @@ program.command("audit").description("Run axe-core powered accessibility audit o
50
50
  process.exit(1);
51
51
  }
52
52
  const allResults = [];
53
- const { createAuditBrowser } = await import("./audit-RM6TCZ5C.js");
53
+ const { createAuditBrowser } = await import("./audit-JYEPKLHR.js");
54
54
  const browser = await createAuditBrowser();
55
55
  try {
56
56
  const auditOptions = { browser };
@@ -122,7 +122,7 @@ program.command("audit").description("Run axe-core powered accessibility audit o
122
122
  process.exit(1);
123
123
  });
124
124
  program.command("test").description("Run core a11y accessibility standard tests on UI components").action(async () => {
125
- const { runTest } = await import("./test-HBPCSYH5.js");
125
+ const { runTest } = await import("./test-6Y4CIQOM.js");
126
126
  runTest();
127
127
  });
128
128
  program.command("build").description("Build accessibility artifacts").addCommand(