aria-ease 3.0.2 → 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);
package/bin/cli.cjs CHANGED
@@ -13261,7 +13261,7 @@ async function runContractTests(componentName, component) {
13261
13261
  const staticFailed = 0;
13262
13262
  reporter.reportStatic(staticPassed, staticFailed);
13263
13263
  reporter.summary(failures);
13264
- return { passes, failures };
13264
+ return { passes, failures, skipped };
13265
13265
  }
13266
13266
  var import_promises, import_meta;
13267
13267
  var init_contractTestRunner = __esm({
@@ -13308,6 +13308,7 @@ async function runContractTestsPlaywright(componentName, url) {
13308
13308
  reporter.start(componentName, totalTests);
13309
13309
  const failures = [];
13310
13310
  const passes = [];
13311
+ const skipped = [];
13311
13312
  let browser = null;
13312
13313
  try {
13313
13314
  browser = await import_playwright3.chromium.launch({ headless: true });
@@ -13315,13 +13316,13 @@ async function runContractTestsPlaywright(componentName, url) {
13315
13316
  const page = await context.newPage();
13316
13317
  await page.goto(url, {
13317
13318
  waitUntil: "domcontentloaded",
13318
- timeout: 6e4
13319
+ timeout: 9e4
13319
13320
  });
13320
13321
  const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
13321
13322
  if (!mainSelector) {
13322
13323
  throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
13323
13324
  }
13324
- await page.waitForSelector(mainSelector, { timeout: 6e4 });
13325
+ await page.waitForSelector(mainSelector, { timeout: 9e4 });
13325
13326
  if (componentName === "menu" && componentContract.selectors.trigger) {
13326
13327
  await page.waitForFunction(
13327
13328
  (selector) => {
@@ -13329,7 +13330,7 @@ async function runContractTestsPlaywright(componentName, url) {
13329
13330
  return trigger && trigger.getAttribute("data-menu-initialized") === "true";
13330
13331
  },
13331
13332
  componentContract.selectors.trigger,
13332
- { timeout: 5e3 }
13333
+ { timeout: 6e3 }
13333
13334
  ).catch(() => {
13334
13335
  console.warn("Menu initialization signal not detected, continuing with tests...");
13335
13336
  });
@@ -13419,7 +13420,7 @@ async function runContractTestsPlaywright(componentName, url) {
13419
13420
  if (componentContract.selectors.input) {
13420
13421
  const inputElement = page.locator(componentContract.selectors.input).first();
13421
13422
  await inputElement.clear();
13422
- await page.waitForTimeout(50);
13423
+ await page.waitForTimeout(100);
13423
13424
  }
13424
13425
  }
13425
13426
  }
@@ -13432,7 +13433,7 @@ async function runContractTestsPlaywright(componentName, url) {
13432
13433
  continue;
13433
13434
  }
13434
13435
  await page.locator(focusSelector).first().focus();
13435
- await page.waitForTimeout(50);
13436
+ await page.waitForTimeout(100);
13436
13437
  }
13437
13438
  if (act.type === "type" && act.value) {
13438
13439
  const typeSelector = componentContract.selectors[act.target];
@@ -13441,7 +13442,7 @@ async function runContractTestsPlaywright(componentName, url) {
13441
13442
  continue;
13442
13443
  }
13443
13444
  await page.locator(typeSelector).first().fill(act.value);
13444
- await page.waitForTimeout(50);
13445
+ await page.waitForTimeout(100);
13445
13446
  }
13446
13447
  if (act.type === "click") {
13447
13448
  if (act.target === "document") {
@@ -13491,7 +13492,7 @@ async function runContractTestsPlaywright(componentName, url) {
13491
13492
  if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
13492
13493
  await page.waitForTimeout(100);
13493
13494
  await page.keyboard.press(keyValue);
13494
- await page.waitForTimeout(50);
13495
+ await page.waitForTimeout(100);
13495
13496
  } else {
13496
13497
  const keypressSelector = componentContract.selectors[act.target];
13497
13498
  if (!keypressSelector) {
@@ -13520,7 +13521,7 @@ async function runContractTestsPlaywright(componentName, url) {
13520
13521
  continue;
13521
13522
  }
13522
13523
  await relativeElement.hover();
13523
- await page.waitForTimeout(50);
13524
+ await page.waitForTimeout(100);
13524
13525
  } else {
13525
13526
  const hoverSelector = componentContract.selectors[act.target];
13526
13527
  if (!hoverSelector) {
@@ -13528,7 +13529,7 @@ async function runContractTestsPlaywright(componentName, url) {
13528
13529
  continue;
13529
13530
  }
13530
13531
  await page.locator(hoverSelector).first().hover();
13531
- await page.waitForTimeout(50);
13532
+ await page.waitForTimeout(100);
13532
13533
  }
13533
13534
  }
13534
13535
  await page.waitForTimeout(100);
@@ -13670,7 +13671,7 @@ async function runContractTestsPlaywright(componentName, url) {
13670
13671
  } finally {
13671
13672
  if (browser) await browser.close();
13672
13673
  }
13673
- return { passes, failures };
13674
+ return { passes, failures, skipped };
13674
13675
  }
13675
13676
  var import_playwright3, import_fs, import_meta2;
13676
13677
  var init_contractTestRunnerPlaywright = __esm({
@@ -13687,15 +13688,49 @@ var init_contractTestRunnerPlaywright = __esm({
13687
13688
 
13688
13689
  // src/utils/test/src/test.ts
13689
13690
  async function testUiComponent(componentName, component, url) {
13690
- 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
+ }
13691
13709
  let contract;
13692
- if (url) {
13693
- console.log(`\u{1F3AD} Running Playwright E2E tests on ${url}`);
13694
- const { runContractTestsPlaywright: runContractTestsPlaywright2 } = await Promise.resolve().then(() => (init_contractTestRunnerPlaywright(), contractTestRunnerPlaywright_exports));
13695
- contract = await runContractTestsPlaywright2(componentName, url);
13696
- } else {
13697
- console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
13698
- 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)}`);
13699
13734
  }
13700
13735
  const result = {
13701
13736
  violations: results.violations,
@@ -13706,10 +13741,11 @@ async function testUiComponent(componentName, component, url) {
13706
13741
  const mode = url ? "Playwright" : "jsdom";
13707
13742
  throw new Error(
13708
13743
  `
13709
- \u274C ${contract.failures.length} assertion${contract.failures.length > 1 ? "s" : ""} failed (${mode} mode)
13710
- \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
13711
13746
 
13712
- \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.`
13713
13749
  );
13714
13750
  }
13715
13751
  if (results.violations.length > 0) {
package/bin/cli.js CHANGED
@@ -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-Q7W3WQEA.js");
207
+ const { runTest } = await import("./test-D374H2ZS.js");
208
208
  runTest();
209
209
  });
210
210
  program.command("help").description("Display help information").action(() => {
@@ -35,6 +35,7 @@ async function runContractTestsPlaywright(componentName, url) {
35
35
  reporter.start(componentName, totalTests);
36
36
  const failures = [];
37
37
  const passes = [];
38
+ const skipped = [];
38
39
  let browser = null;
39
40
  try {
40
41
  browser = await chromium.launch({ headless: true });
@@ -42,13 +43,13 @@ async function runContractTestsPlaywright(componentName, url) {
42
43
  const page = await context.newPage();
43
44
  await page.goto(url, {
44
45
  waitUntil: "domcontentloaded",
45
- timeout: 6e4
46
+ timeout: 9e4
46
47
  });
47
48
  const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
48
49
  if (!mainSelector) {
49
50
  throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
50
51
  }
51
- await page.waitForSelector(mainSelector, { timeout: 6e4 });
52
+ await page.waitForSelector(mainSelector, { timeout: 9e4 });
52
53
  if (componentName === "menu" && componentContract.selectors.trigger) {
53
54
  await page.waitForFunction(
54
55
  (selector) => {
@@ -56,7 +57,7 @@ async function runContractTestsPlaywright(componentName, url) {
56
57
  return trigger && trigger.getAttribute("data-menu-initialized") === "true";
57
58
  },
58
59
  componentContract.selectors.trigger,
59
- { timeout: 5e3 }
60
+ { timeout: 6e3 }
60
61
  ).catch(() => {
61
62
  console.warn("Menu initialization signal not detected, continuing with tests...");
62
63
  });
@@ -146,7 +147,7 @@ async function runContractTestsPlaywright(componentName, url) {
146
147
  if (componentContract.selectors.input) {
147
148
  const inputElement = page.locator(componentContract.selectors.input).first();
148
149
  await inputElement.clear();
149
- await page.waitForTimeout(50);
150
+ await page.waitForTimeout(100);
150
151
  }
151
152
  }
152
153
  }
@@ -159,7 +160,7 @@ async function runContractTestsPlaywright(componentName, url) {
159
160
  continue;
160
161
  }
161
162
  await page.locator(focusSelector).first().focus();
162
- await page.waitForTimeout(50);
163
+ await page.waitForTimeout(100);
163
164
  }
164
165
  if (act.type === "type" && act.value) {
165
166
  const typeSelector = componentContract.selectors[act.target];
@@ -168,7 +169,7 @@ async function runContractTestsPlaywright(componentName, url) {
168
169
  continue;
169
170
  }
170
171
  await page.locator(typeSelector).first().fill(act.value);
171
- await page.waitForTimeout(50);
172
+ await page.waitForTimeout(100);
172
173
  }
173
174
  if (act.type === "click") {
174
175
  if (act.target === "document") {
@@ -218,7 +219,7 @@ async function runContractTestsPlaywright(componentName, url) {
218
219
  if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
219
220
  await page.waitForTimeout(100);
220
221
  await page.keyboard.press(keyValue);
221
- await page.waitForTimeout(50);
222
+ await page.waitForTimeout(100);
222
223
  } else {
223
224
  const keypressSelector = componentContract.selectors[act.target];
224
225
  if (!keypressSelector) {
@@ -247,7 +248,7 @@ async function runContractTestsPlaywright(componentName, url) {
247
248
  continue;
248
249
  }
249
250
  await relativeElement.hover();
250
- await page.waitForTimeout(50);
251
+ await page.waitForTimeout(100);
251
252
  } else {
252
253
  const hoverSelector = componentContract.selectors[act.target];
253
254
  if (!hoverSelector) {
@@ -255,7 +256,7 @@ async function runContractTestsPlaywright(componentName, url) {
255
256
  continue;
256
257
  }
257
258
  await page.locator(hoverSelector).first().hover();
258
- await page.waitForTimeout(50);
259
+ await page.waitForTimeout(100);
259
260
  }
260
261
  }
261
262
  await page.waitForTimeout(100);
@@ -397,7 +398,7 @@ async function runContractTestsPlaywright(componentName, url) {
397
398
  } finally {
398
399
  if (browser) await browser.close();
399
400
  }
400
- return { passes, failures };
401
+ return { passes, failures, skipped };
401
402
  }
402
403
  export {
403
404
  runContractTestsPlaywright
@@ -12741,20 +12741,54 @@ async function runContractTests(componentName, component) {
12741
12741
  const staticFailed = 0;
12742
12742
  reporter.reportStatic(staticPassed, staticFailed);
12743
12743
  reporter.summary(failures);
12744
- return { passes, failures };
12744
+ return { passes, failures, skipped };
12745
12745
  }
12746
12746
 
12747
12747
  // src/utils/test/src/test.ts
12748
12748
  async function testUiComponent(componentName, component, url) {
12749
- const results = await axe(component);
12749
+ if (!componentName || typeof componentName !== "string") {
12750
+ throw new Error("\u274C testUiComponent requires a valid componentName (string)");
12751
+ }
12752
+ if (!component || !(component instanceof HTMLElement)) {
12753
+ throw new Error("\u274C testUiComponent requires a valid component (HTMLElement)");
12754
+ }
12755
+ if (url && typeof url !== "string") {
12756
+ throw new Error("\u274C testUiComponent url parameter must be a string");
12757
+ }
12758
+ let results;
12759
+ try {
12760
+ results = await axe(component);
12761
+ } catch (error) {
12762
+ throw new Error(
12763
+ `\u274C Axe accessibility scan failed
12764
+ Error: ${error instanceof Error ? error.message : String(error)}`
12765
+ );
12766
+ }
12750
12767
  let contract;
12751
- if (url) {
12752
- console.log(`\u{1F3AD} Running Playwright E2E tests on ${url}`);
12753
- const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-TLQZGKW7.js");
12754
- contract = await runContractTestsPlaywright(componentName, url);
12755
- } else {
12756
- console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
12757
- contract = await runContractTests(componentName, component);
12768
+ try {
12769
+ if (url) {
12770
+ console.log(`\u{1F3AD} Running Playwright E2E tests on ${url}`);
12771
+ try {
12772
+ new URL(url);
12773
+ } catch {
12774
+ throw new Error(
12775
+ `\u274C Invalid URL format: "${url}"
12776
+ URL must include protocol (e.g., "http://localhost:5173/test")`
12777
+ );
12778
+ }
12779
+ const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-3VJUZSYK.js");
12780
+ contract = await runContractTestsPlaywright(componentName, url);
12781
+ } else {
12782
+ console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
12783
+ console.log(`Some tests may be skipped or yield false positives/negatives.
12784
+ For full coverage, run with a URL to enable Playwright E2E tests.`);
12785
+ contract = await runContractTests(componentName, component);
12786
+ }
12787
+ } catch (error) {
12788
+ if (error instanceof Error) {
12789
+ throw error;
12790
+ }
12791
+ throw new Error(`\u274C Contract test execution failed: ${String(error)}`);
12758
12792
  }
12759
12793
  const result = {
12760
12794
  violations: results.violations,
@@ -12765,10 +12799,11 @@ async function testUiComponent(componentName, component, url) {
12765
12799
  const mode = url ? "Playwright" : "jsdom";
12766
12800
  throw new Error(
12767
12801
  `
12768
- \u274C ${contract.failures.length} assertion${contract.failures.length > 1 ? "s" : ""} failed (${mode} mode)
12769
- \u2705 ${contract.passes.length} assertion${contract.passes.length > 1 ? "s" : ""} passed
12802
+ \u274C ${contract.failures.length} accessibility contract test${contract.failures.length > 1 ? "s" : ""} failed (${mode} mode)
12803
+ \u2705 ${contract.passes.length} test${contract.passes.length > 1 ? "s" : ""} passed
12770
12804
 
12771
- \u{1F4CB} Review the detailed test report above for specific failures.`
12805
+ \u{1F4CB} Review the detailed test report above for specific failures.
12806
+ \u{1F4A1} Contract tests validate ARIA attributes and keyboard interactions per W3C APG guidelines.`
12772
12807
  );
12773
12808
  }
12774
12809
  if (results.violations.length > 0) {
@@ -33,6 +33,7 @@ async function runContractTestsPlaywright(componentName, url) {
33
33
  reporter.start(componentName, totalTests);
34
34
  const failures = [];
35
35
  const passes = [];
36
+ const skipped = [];
36
37
  let browser = null;
37
38
  try {
38
39
  browser = await chromium.launch({ headless: true });
@@ -40,13 +41,13 @@ async function runContractTestsPlaywright(componentName, url) {
40
41
  const page = await context.newPage();
41
42
  await page.goto(url, {
42
43
  waitUntil: "domcontentloaded",
43
- timeout: 6e4
44
+ timeout: 9e4
44
45
  });
45
46
  const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
46
47
  if (!mainSelector) {
47
48
  throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
48
49
  }
49
- await page.waitForSelector(mainSelector, { timeout: 6e4 });
50
+ await page.waitForSelector(mainSelector, { timeout: 9e4 });
50
51
  if (componentName === "menu" && componentContract.selectors.trigger) {
51
52
  await page.waitForFunction(
52
53
  (selector) => {
@@ -54,7 +55,7 @@ async function runContractTestsPlaywright(componentName, url) {
54
55
  return trigger && trigger.getAttribute("data-menu-initialized") === "true";
55
56
  },
56
57
  componentContract.selectors.trigger,
57
- { timeout: 5e3 }
58
+ { timeout: 6e3 }
58
59
  ).catch(() => {
59
60
  console.warn("Menu initialization signal not detected, continuing with tests...");
60
61
  });
@@ -144,7 +145,7 @@ async function runContractTestsPlaywright(componentName, url) {
144
145
  if (componentContract.selectors.input) {
145
146
  const inputElement = page.locator(componentContract.selectors.input).first();
146
147
  await inputElement.clear();
147
- await page.waitForTimeout(50);
148
+ await page.waitForTimeout(100);
148
149
  }
149
150
  }
150
151
  }
@@ -157,7 +158,7 @@ async function runContractTestsPlaywright(componentName, url) {
157
158
  continue;
158
159
  }
159
160
  await page.locator(focusSelector).first().focus();
160
- await page.waitForTimeout(50);
161
+ await page.waitForTimeout(100);
161
162
  }
162
163
  if (act.type === "type" && act.value) {
163
164
  const typeSelector = componentContract.selectors[act.target];
@@ -166,7 +167,7 @@ async function runContractTestsPlaywright(componentName, url) {
166
167
  continue;
167
168
  }
168
169
  await page.locator(typeSelector).first().fill(act.value);
169
- await page.waitForTimeout(50);
170
+ await page.waitForTimeout(100);
170
171
  }
171
172
  if (act.type === "click") {
172
173
  if (act.target === "document") {
@@ -216,7 +217,7 @@ async function runContractTestsPlaywright(componentName, url) {
216
217
  if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
217
218
  await page.waitForTimeout(100);
218
219
  await page.keyboard.press(keyValue);
219
- await page.waitForTimeout(50);
220
+ await page.waitForTimeout(100);
220
221
  } else {
221
222
  const keypressSelector = componentContract.selectors[act.target];
222
223
  if (!keypressSelector) {
@@ -245,7 +246,7 @@ async function runContractTestsPlaywright(componentName, url) {
245
246
  continue;
246
247
  }
247
248
  await relativeElement.hover();
248
- await page.waitForTimeout(50);
249
+ await page.waitForTimeout(100);
249
250
  } else {
250
251
  const hoverSelector = componentContract.selectors[act.target];
251
252
  if (!hoverSelector) {
@@ -253,7 +254,7 @@ async function runContractTestsPlaywright(componentName, url) {
253
254
  continue;
254
255
  }
255
256
  await page.locator(hoverSelector).first().hover();
256
- await page.waitForTimeout(50);
257
+ await page.waitForTimeout(100);
257
258
  }
258
259
  }
259
260
  await page.waitForTimeout(100);
@@ -395,7 +396,7 @@ async function runContractTestsPlaywright(componentName, url) {
395
396
  } finally {
396
397
  if (browser) await browser.close();
397
398
  }
398
- return { passes, failures };
399
+ return { passes, failures, skipped };
399
400
  }
400
401
  export {
401
402
  runContractTestsPlaywright