aria-ease 3.0.1 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -172,7 +172,7 @@ updateAccordionTriggerAriaAttributes(
172
172
  "accordion-container", // Container ID
173
173
  "accordion-trigger", // Shared class for triggers
174
174
  accordionStates, // State array
175
- 0 // Index of trigger that changed
175
+ 0, // Index of trigger that changed
176
176
  );
177
177
  ```
178
178
 
@@ -223,7 +223,7 @@ function handleCheckboxClick(index) {
223
223
  "checkbox-group",
224
224
  "custom-checkbox",
225
225
  checkboxStates,
226
- index
226
+ index,
227
227
  );
228
228
  }
229
229
  ```
@@ -314,14 +314,14 @@ Aria-Ease includes a built-in testing framework for automated accessibility vali
314
314
  import { testUiComponent } from "aria-ease/test";
315
315
 
316
316
  // In your test file (Vitest, Jest, etc.)
317
- test("menu is accessible", async () => {
318
- const { container } = render(<MyMenu />);
317
+ test("combobox is accessible", async () => {
318
+ const { container } = render(<Combobox />);
319
319
 
320
320
  // Runs axe-core + contract tests
321
321
  const result = await testUiComponent(
322
- "menu",
322
+ "combobox",
323
323
  container,
324
- "http://localhost:3000" // Optional: full E2E with Playwright
324
+ "http://localhost:3000", // Optional: full E2E with Playwright
325
325
  );
326
326
 
327
327
  expect(result.violations).toHaveLength(0);
@@ -1,4 +1,4 @@
1
- import "./chunk-JSBRDJBE.js";
1
+ import "./chunk-2P3A4VVY.js";
2
2
 
3
3
  // src/utils/audit/src/audit/audit.ts
4
4
  import AxeBuilder from "@axe-core/playwright";
@@ -7,6 +7,10 @@ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
7
  var __commonJS = (cb, mod) => function __require() {
8
8
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
9
  };
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
10
14
  var __copyProps = (to, from, except, desc) => {
11
15
  if (from && typeof from === "object" || typeof from === "function") {
12
16
  for (let key of __getOwnPropNames(from))
@@ -15,6 +19,7 @@ var __copyProps = (to, from, except, desc) => {
15
19
  }
16
20
  return to;
17
21
  };
22
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
18
23
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
24
  // If the importer is in node compatibility mode or this is not an ESM
20
25
  // file that has been converted to a CommonJS file using a Babel-
@@ -26,5 +31,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
31
 
27
32
  export {
28
33
  __commonJS,
34
+ __export,
35
+ __reExport,
29
36
  __toESM
30
37
  };
package/bin/cli.cjs CHANGED
@@ -24,6 +24,7 @@ var __copyProps = (to, from, except, desc) => {
24
24
  }
25
25
  return to;
26
26
  };
27
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
27
28
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
28
29
  // If the importer is in node compatibility mode or this is not an ESM
29
30
  // file that has been converted to a CommonJS file using a Babel-
@@ -13260,7 +13261,7 @@ async function runContractTests(componentName, component) {
13260
13261
  const staticFailed = 0;
13261
13262
  reporter.reportStatic(staticPassed, staticFailed);
13262
13263
  reporter.summary(failures);
13263
- return { passes, failures };
13264
+ return { passes, failures, skipped };
13264
13265
  }
13265
13266
  var import_promises, import_meta;
13266
13267
  var init_contractTestRunner = __esm({
@@ -13274,6 +13275,20 @@ var init_contractTestRunner = __esm({
13274
13275
  }
13275
13276
  });
13276
13277
 
13278
+ // node_modules/@playwright/test/index.mjs
13279
+ var test_exports = {};
13280
+ __export(test_exports, {
13281
+ default: () => import_test.default
13282
+ });
13283
+ var import_test;
13284
+ var init_test = __esm({
13285
+ "node_modules/@playwright/test/index.mjs"() {
13286
+ "use strict";
13287
+ __reExport(test_exports, require("playwright/test"));
13288
+ import_test = __toESM(require("playwright/test"), 1);
13289
+ }
13290
+ });
13291
+
13277
13292
  // src/utils/test/contract/contractTestRunnerPlaywright.ts
13278
13293
  var contractTestRunnerPlaywright_exports = {};
13279
13294
  __export(contractTestRunnerPlaywright_exports, {
@@ -13293,6 +13308,7 @@ async function runContractTestsPlaywright(componentName, url) {
13293
13308
  reporter.start(componentName, totalTests);
13294
13309
  const failures = [];
13295
13310
  const passes = [];
13311
+ const skipped = [];
13296
13312
  let browser = null;
13297
13313
  try {
13298
13314
  browser = await import_playwright3.chromium.launch({ headless: true });
@@ -13300,13 +13316,25 @@ async function runContractTestsPlaywright(componentName, url) {
13300
13316
  const page = await context.newPage();
13301
13317
  await page.goto(url, {
13302
13318
  waitUntil: "domcontentloaded",
13303
- timeout: 6e4
13319
+ timeout: 9e4
13304
13320
  });
13305
13321
  const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
13306
13322
  if (!mainSelector) {
13307
13323
  throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
13308
13324
  }
13309
- await page.waitForSelector(mainSelector, { timeout: 6e4 });
13325
+ await page.waitForSelector(mainSelector, { timeout: 9e4 });
13326
+ if (componentName === "menu" && componentContract.selectors.trigger) {
13327
+ await page.waitForFunction(
13328
+ (selector) => {
13329
+ const trigger = document.querySelector(selector);
13330
+ return trigger && trigger.getAttribute("data-menu-initialized") === "true";
13331
+ },
13332
+ componentContract.selectors.trigger,
13333
+ { timeout: 6e3 }
13334
+ ).catch(() => {
13335
+ console.warn("Menu initialization signal not detected, continuing with tests...");
13336
+ });
13337
+ }
13310
13338
  async function resolveRelativeTarget(selector, relative) {
13311
13339
  const items = await page.locator(selector).all();
13312
13340
  switch (relative) {
@@ -13392,7 +13420,7 @@ async function runContractTestsPlaywright(componentName, url) {
13392
13420
  if (componentContract.selectors.input) {
13393
13421
  const inputElement = page.locator(componentContract.selectors.input).first();
13394
13422
  await inputElement.clear();
13395
- await page.waitForTimeout(50);
13423
+ await page.waitForTimeout(100);
13396
13424
  }
13397
13425
  }
13398
13426
  }
@@ -13405,7 +13433,7 @@ async function runContractTestsPlaywright(componentName, url) {
13405
13433
  continue;
13406
13434
  }
13407
13435
  await page.locator(focusSelector).first().focus();
13408
- await page.waitForTimeout(50);
13436
+ await page.waitForTimeout(100);
13409
13437
  }
13410
13438
  if (act.type === "type" && act.value) {
13411
13439
  const typeSelector = componentContract.selectors[act.target];
@@ -13414,7 +13442,7 @@ async function runContractTestsPlaywright(componentName, url) {
13414
13442
  continue;
13415
13443
  }
13416
13444
  await page.locator(typeSelector).first().fill(act.value);
13417
- await page.waitForTimeout(50);
13445
+ await page.waitForTimeout(100);
13418
13446
  }
13419
13447
  if (act.type === "click") {
13420
13448
  if (act.target === "document") {
@@ -13431,7 +13459,7 @@ async function runContractTestsPlaywright(componentName, url) {
13431
13459
  continue;
13432
13460
  }
13433
13461
  await relativeElement.click();
13434
- await page.waitForTimeout(200);
13462
+ await page.waitForTimeout(componentName === "menu" ? 500 : 200);
13435
13463
  } else {
13436
13464
  const actionSelector = componentContract.selectors[act.target];
13437
13465
  if (!actionSelector) {
@@ -13439,7 +13467,7 @@ async function runContractTestsPlaywright(componentName, url) {
13439
13467
  continue;
13440
13468
  }
13441
13469
  await page.locator(actionSelector).first().click();
13442
- await page.waitForTimeout(200);
13470
+ await page.waitForTimeout(componentName === "menu" ? 500 : 200);
13443
13471
  }
13444
13472
  }
13445
13473
  if (act.type === "keypress" && act.key) {
@@ -13464,7 +13492,7 @@ async function runContractTestsPlaywright(componentName, url) {
13464
13492
  if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
13465
13493
  await page.waitForTimeout(100);
13466
13494
  await page.keyboard.press(keyValue);
13467
- await page.waitForTimeout(50);
13495
+ await page.waitForTimeout(100);
13468
13496
  } else {
13469
13497
  const keypressSelector = componentContract.selectors[act.target];
13470
13498
  if (!keypressSelector) {
@@ -13493,7 +13521,7 @@ async function runContractTestsPlaywright(componentName, url) {
13493
13521
  continue;
13494
13522
  }
13495
13523
  await relativeElement.hover();
13496
- await page.waitForTimeout(50);
13524
+ await page.waitForTimeout(100);
13497
13525
  } else {
13498
13526
  const hoverSelector = componentContract.selectors[act.target];
13499
13527
  if (!hoverSelector) {
@@ -13501,7 +13529,7 @@ async function runContractTestsPlaywright(componentName, url) {
13501
13529
  continue;
13502
13530
  }
13503
13531
  await page.locator(hoverSelector).first().hover();
13504
- await page.waitForTimeout(50);
13532
+ await page.waitForTimeout(100);
13505
13533
  }
13506
13534
  }
13507
13535
  await page.waitForTimeout(100);
@@ -13533,32 +13561,48 @@ async function runContractTestsPlaywright(componentName, url) {
13533
13561
  continue;
13534
13562
  }
13535
13563
  if (assertion.assertion === "toBeVisible") {
13536
- const isVisible = await target.isVisible();
13537
- if (isVisible) {
13564
+ try {
13565
+ await (0, test_exports.expect)(target).toBeVisible({ timeout: 3e3 });
13538
13566
  passes.push(`${assertion.target} is visible as expected. Test: "${dynamicTest.description}".`);
13539
- } else {
13540
- failures.push(`${assertion.failureMessage}`);
13567
+ } catch {
13568
+ const debugState = await page.evaluate((sel) => {
13569
+ const el = sel ? document.querySelector(sel) : null;
13570
+ if (!el) return "element not found";
13571
+ const styles = window.getComputedStyle(el);
13572
+ return `display:${styles.display}, visibility:${styles.visibility}, opacity:${styles.opacity}`;
13573
+ }, componentContract.selectors[assertion.target] || "");
13574
+ failures.push(`${assertion.failureMessage} (actual: ${debugState})`);
13541
13575
  }
13542
13576
  }
13543
13577
  if (assertion.assertion === "notToBeVisible") {
13544
- const isVisible = await target.isVisible();
13545
- if (!isVisible) {
13578
+ try {
13579
+ await (0, test_exports.expect)(target).toBeHidden({ timeout: 5e3 });
13546
13580
  passes.push(`${assertion.target} is not visible as expected. Test: "${dynamicTest.description}".`);
13547
- } else {
13548
- failures.push(assertion.failureMessage + ` ${assertion.target} is still visible.`);
13581
+ } catch {
13582
+ const debugState = await page.evaluate((sel) => {
13583
+ const el = sel ? document.querySelector(sel) : null;
13584
+ if (!el) return "element not found";
13585
+ const styles = window.getComputedStyle(el);
13586
+ return `display:${styles.display}, visibility:${styles.visibility}, opacity:${styles.opacity}`;
13587
+ }, componentContract.selectors[assertion.target] || "");
13588
+ failures.push(assertion.failureMessage + ` ${assertion.target} is still visible (actual: ${debugState}).`);
13549
13589
  }
13550
13590
  }
13551
13591
  if (assertion.assertion === "toHaveAttribute" && assertion.attribute && assertion.expectedValue) {
13552
- const attributeValue = await target.getAttribute(assertion.attribute);
13553
- if (assertion.expectedValue === "!empty") {
13554
- if (attributeValue && attributeValue.trim() !== "") {
13555
- passes.push(`${assertion.target} has non-empty "${assertion.attribute}". Test: "${dynamicTest.description}".`);
13592
+ try {
13593
+ if (assertion.expectedValue === "!empty") {
13594
+ const attributeValue = await target.getAttribute(assertion.attribute);
13595
+ if (attributeValue && attributeValue.trim() !== "") {
13596
+ passes.push(`${assertion.target} has non-empty "${assertion.attribute}". Test: "${dynamicTest.description}".`);
13597
+ } else {
13598
+ failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should not be empty, found "${attributeValue}".`);
13599
+ }
13556
13600
  } else {
13557
- failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should not be empty, found "${attributeValue}".`);
13601
+ await (0, test_exports.expect)(target).toHaveAttribute(assertion.attribute, assertion.expectedValue, { timeout: 3e3 });
13602
+ passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
13558
13603
  }
13559
- } else if (attributeValue === assertion.expectedValue) {
13560
- passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
13561
- } else {
13604
+ } catch {
13605
+ const attributeValue = await target.getAttribute(assertion.attribute);
13562
13606
  failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should be "${assertion.expectedValue}", found "${attributeValue}".`);
13563
13607
  }
13564
13608
  }
@@ -13583,10 +13627,10 @@ async function runContractTestsPlaywright(componentName, url) {
13583
13627
  }
13584
13628
  }
13585
13629
  if (assertion.assertion === "toHaveFocus") {
13586
- const hasFocus = await target.evaluate((el) => el === document.activeElement);
13587
- if (hasFocus) {
13630
+ try {
13631
+ await (0, test_exports.expect)(target).toBeFocused({ timeout: 5e3 });
13588
13632
  passes.push(`${assertion.target} has focus as expected. Test: "${dynamicTest.description}".`);
13589
- } else {
13633
+ } catch {
13590
13634
  failures.push(`${assertion.failureMessage}`);
13591
13635
  }
13592
13636
  }
@@ -13627,13 +13671,14 @@ async function runContractTestsPlaywright(componentName, url) {
13627
13671
  } finally {
13628
13672
  if (browser) await browser.close();
13629
13673
  }
13630
- return { passes, failures };
13674
+ return { passes, failures, skipped };
13631
13675
  }
13632
13676
  var import_playwright3, import_fs, import_meta2;
13633
13677
  var init_contractTestRunnerPlaywright = __esm({
13634
13678
  "src/utils/test/contract/contractTestRunnerPlaywright.ts"() {
13635
13679
  "use strict";
13636
13680
  import_playwright3 = require("playwright");
13681
+ init_test();
13637
13682
  import_fs = require("fs");
13638
13683
  init_contract();
13639
13684
  init_ContractReporter();
@@ -13643,15 +13688,49 @@ var init_contractTestRunnerPlaywright = __esm({
13643
13688
 
13644
13689
  // src/utils/test/src/test.ts
13645
13690
  async function testUiComponent(componentName, component, url) {
13646
- const results = await (0, import_jest_axe.axe)(component);
13691
+ if (!componentName || typeof componentName !== "string") {
13692
+ throw new Error("\u274C testUiComponent requires a valid componentName (string)");
13693
+ }
13694
+ if (!component || !(component instanceof HTMLElement)) {
13695
+ throw new Error("\u274C testUiComponent requires a valid component (HTMLElement)");
13696
+ }
13697
+ if (url && typeof url !== "string") {
13698
+ throw new Error("\u274C testUiComponent url parameter must be a string");
13699
+ }
13700
+ let results;
13701
+ try {
13702
+ results = await (0, import_jest_axe.axe)(component);
13703
+ } catch (error) {
13704
+ throw new Error(
13705
+ `\u274C Axe accessibility scan failed
13706
+ Error: ${error instanceof Error ? error.message : String(error)}`
13707
+ );
13708
+ }
13647
13709
  let contract;
13648
- if (url) {
13649
- console.log(`\u{1F3AD} Running Playwright E2E tests on ${url}`);
13650
- const { runContractTestsPlaywright: runContractTestsPlaywright2 } = await Promise.resolve().then(() => (init_contractTestRunnerPlaywright(), contractTestRunnerPlaywright_exports));
13651
- contract = await runContractTestsPlaywright2(componentName, url);
13652
- } else {
13653
- console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
13654
- contract = await runContractTests(componentName, component);
13710
+ try {
13711
+ if (url) {
13712
+ console.log(`\u{1F3AD} Running Playwright E2E tests on ${url}`);
13713
+ try {
13714
+ new URL(url);
13715
+ } catch {
13716
+ throw new Error(
13717
+ `\u274C Invalid URL format: "${url}"
13718
+ URL must include protocol (e.g., "http://localhost:5173/test")`
13719
+ );
13720
+ }
13721
+ const { runContractTestsPlaywright: runContractTestsPlaywright2 } = await Promise.resolve().then(() => (init_contractTestRunnerPlaywright(), contractTestRunnerPlaywright_exports));
13722
+ contract = await runContractTestsPlaywright2(componentName, url);
13723
+ } else {
13724
+ console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
13725
+ console.log(`Some tests may be skipped or yield false positives/negatives.
13726
+ For full coverage, run with a URL to enable Playwright E2E tests.`);
13727
+ contract = await runContractTests(componentName, component);
13728
+ }
13729
+ } catch (error) {
13730
+ if (error instanceof Error) {
13731
+ throw error;
13732
+ }
13733
+ throw new Error(`\u274C Contract test execution failed: ${String(error)}`);
13655
13734
  }
13656
13735
  const result = {
13657
13736
  violations: results.violations,
@@ -13662,10 +13741,11 @@ async function testUiComponent(componentName, component, url) {
13662
13741
  const mode = url ? "Playwright" : "jsdom";
13663
13742
  throw new Error(
13664
13743
  `
13665
- \u274C ${contract.failures.length} assertion${contract.failures.length > 1 ? "s" : ""} failed (${mode} mode)
13666
- \u2705 ${contract.passes.length} assertion${contract.passes.length > 1 ? "s" : ""} passed
13744
+ \u274C ${contract.failures.length} accessibility contract test${contract.failures.length > 1 ? "s" : ""} failed (${mode} mode)
13745
+ \u2705 ${contract.passes.length} test${contract.passes.length > 1 ? "s" : ""} passed
13667
13746
 
13668
- \u{1F4CB} Review the detailed test report above for specific failures.`
13747
+ \u{1F4CB} Review the detailed test report above for specific failures.
13748
+ \u{1F4A1} Contract tests validate ARIA attributes and keyboard interactions per W3C APG guidelines.`
13669
13749
  );
13670
13750
  }
13671
13751
  if (results.violations.length > 0) {
@@ -13688,7 +13768,7 @@ ${violationDetails}
13688
13768
  return result;
13689
13769
  }
13690
13770
  var import_jest_axe, runTest;
13691
- var init_test = __esm({
13771
+ var init_test2 = __esm({
13692
13772
  "src/utils/test/src/test.ts"() {
13693
13773
  "use strict";
13694
13774
  import_jest_axe = require("jest-axe");
@@ -13721,15 +13801,15 @@ var init_test = __esm({
13721
13801
  });
13722
13802
 
13723
13803
  // src/utils/test/index.ts
13724
- var test_exports = {};
13725
- __export(test_exports, {
13804
+ var test_exports2 = {};
13805
+ __export(test_exports2, {
13726
13806
  runTest: () => runTest,
13727
13807
  testUiComponent: () => testUiComponent
13728
13808
  });
13729
- var init_test2 = __esm({
13809
+ var init_test3 = __esm({
13730
13810
  "src/utils/test/index.ts"() {
13731
13811
  "use strict";
13732
- init_test();
13812
+ init_test2();
13733
13813
  }
13734
13814
  });
13735
13815
 
@@ -13936,7 +14016,7 @@ program.command("audit").description("Run axe-core powered accessibility audit o
13936
14016
  console.log(import_chalk.default.green("\n\u{1F389} All audits completed."));
13937
14017
  });
13938
14018
  program.command("test").description("Run core a11y accessibility standard tests on UI components").action(async () => {
13939
- const { runTest: runTest2 } = await Promise.resolve().then(() => (init_test2(), test_exports));
14019
+ const { runTest: runTest2 } = await Promise.resolve().then(() => (init_test3(), test_exports2));
13940
14020
  runTest2();
13941
14021
  });
13942
14022
  program.command("help").description("Display help information").action(() => {
package/bin/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-JSBRDJBE.js";
2
+ import "./chunk-2P3A4VVY.js";
3
3
 
4
4
  // src/utils/cli/cli.ts
5
5
  import { Command } from "commander";
@@ -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-XZJXMUPL.js");
132
- const { formatResults } = await import("./formatters-U4E5EVPL.js");
131
+ const { runAudit } = await import("./audit-6A7OW5NJ.js");
132
+ const { formatResults } = await import("./formatters-FCDHFTPI.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-PK5MBHIN.js");
207
+ const { runTest } = await import("./test-D374H2ZS.js");
208
208
  runTest();
209
209
  });
210
210
  program.command("help").description("Display help information").action(() => {