aria-ease 6.12.1 → 6.14.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.
@@ -585,7 +585,7 @@ var init_MenuComponentStrategy = __esm({
585
585
  if (!closeSelector && this.selectors.focusable) {
586
586
  closeSelector = this.selectors.focusable;
587
587
  } else if (!closeSelector) {
588
- closeSelector = this.selectors.trigger;
588
+ closeSelector = this.selectors.main;
589
589
  }
590
590
  if (closeSelector) {
591
591
  const closeElement = page.locator(closeSelector).first();
@@ -593,8 +593,8 @@ var init_MenuComponentStrategy = __esm({
593
593
  await page.keyboard.press("Escape");
594
594
  menuClosed = await test.expect(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
595
595
  }
596
- if (!menuClosed && this.selectors.trigger) {
597
- const triggerElement = page.locator(this.selectors.trigger).first();
596
+ if (!menuClosed && this.selectors.main) {
597
+ const triggerElement = page.locator(this.selectors.main).first();
598
598
  await triggerElement.click({ timeout: this.actionTimeoutMs });
599
599
  menuClosed = await test.expect(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
600
600
  }
@@ -614,8 +614,8 @@ This indicates a problem with the menu component's close functionality.`
614
614
  if (this.selectors.input) {
615
615
  await page.locator(this.selectors.input).first().clear();
616
616
  }
617
- if (this.selectors.trigger) {
618
- const triggerElement = page.locator(this.selectors.trigger).first();
617
+ if (this.selectors.main) {
618
+ const triggerElement = page.locator(this.selectors.main).first();
619
619
  await triggerElement.focus();
620
620
  }
621
621
  }
@@ -1385,13 +1385,21 @@ var init_AssertionRunner = __esm({
1385
1385
  /**
1386
1386
  * Validate focus assertion
1387
1387
  */
1388
- async validateFocus(target, targetName, failureMessage, testDescription) {
1388
+ async validateFocus(target, targetName, expectedFocus, failureMessage, testDescription) {
1389
1389
  try {
1390
- await test.expect(target).toBeFocused({ timeout: this.timeoutMs });
1391
- return {
1392
- success: true,
1393
- passMessage: `${targetName} has focus as expected. Test: "${testDescription}".`
1394
- };
1390
+ if (expectedFocus) {
1391
+ await test.expect(target).toBeFocused({ timeout: this.timeoutMs });
1392
+ return {
1393
+ success: true,
1394
+ passMessage: `${targetName} has focus as expected. Test: "${testDescription}".`
1395
+ };
1396
+ } else {
1397
+ await test.expect(target).not.toBeFocused({ timeout: this.timeoutMs });
1398
+ return {
1399
+ success: true,
1400
+ passMessage: `${targetName} does not have focus as expected. Test: "${testDescription}".`
1401
+ };
1402
+ }
1395
1403
  } catch {
1396
1404
  const actualFocus = await this.page.evaluate(() => {
1397
1405
  const focused = document.activeElement;
@@ -1477,7 +1485,9 @@ var init_AssertionRunner = __esm({
1477
1485
  }
1478
1486
  return { success: false, failMessage: "Missing expectedValue for toHaveValue assertion" };
1479
1487
  case "toHaveFocus":
1480
- return this.validateFocus(target, assertion.target, assertion.failureMessage || "", testDescription);
1488
+ return this.validateFocus(target, assertion.target, true, assertion.failureMessage || "", testDescription);
1489
+ case "notToHaveFocus":
1490
+ return this.validateFocus(target, assertion.target, false, assertion.failureMessage || "", testDescription);
1481
1491
  case "toHaveRole":
1482
1492
  if (assertion.expectedValue !== void 0) {
1483
1493
  return this.validateRole(target, assertion.target, assertion.expectedValue, assertion.failureMessage || "", testDescription);
@@ -1500,12 +1510,7 @@ async function runContractTestsPlaywright(componentName, url, strictness, config
1500
1510
  const componentConfig = config?.test?.components?.find((c) => c.name === componentName);
1501
1511
  const isCustomContract = !!componentConfig?.contractPath;
1502
1512
  const reporter = new ContractReporter(true, isCustomContract);
1503
- const defaultTimeouts = {
1504
- actionTimeoutMs: 400,
1505
- assertionTimeoutMs: 400,
1506
- navigationTimeoutMs: 3e4,
1507
- componentReadyTimeoutMs: 5e3
1508
- };
1513
+ const defaultTimeouts = { actionTimeoutMs: 400, assertionTimeoutMs: 400, navigationTimeoutMs: 3e4, componentReadyTimeoutMs: 5e3 };
1509
1514
  const globalDisableTimeouts = config?.test?.disableTimeouts === true;
1510
1515
  const componentDisableTimeouts = componentConfig?.disableTimeouts === true;
1511
1516
  const disableTimeouts = componentDisableTimeouts || globalDisableTimeouts;
@@ -1517,11 +1522,7 @@ async function runContractTestsPlaywright(componentName, url, strictness, config
1517
1522
  }
1518
1523
  return value;
1519
1524
  };
1520
- const actionTimeoutMs = resolveTimeout(
1521
- componentConfig?.actionTimeoutMs,
1522
- config?.test?.actionTimeoutMs,
1523
- defaultTimeouts.actionTimeoutMs
1524
- );
1525
+ const actionTimeoutMs = resolveTimeout(componentConfig?.actionTimeoutMs, config?.test?.actionTimeoutMs, defaultTimeouts.actionTimeoutMs);
1525
1526
  const assertionTimeoutMs = resolveTimeout(
1526
1527
  componentConfig?.assertionTimeoutMs,
1527
1528
  config?.test?.assertionTimeoutMs,
@@ -1621,8 +1622,8 @@ This usually means:
1621
1622
  );
1622
1623
  }
1623
1624
  reporter.start(componentName, totalTests, apgUrl);
1624
- if (componentName === "menu" && componentContract.selectors.trigger) {
1625
- await page.locator(componentContract.selectors.trigger).first().waitFor({ state: "attached", timeout: componentReadyTimeoutMs }).catch(() => {
1625
+ if (componentName === "menu" && componentContract.selectors.main) {
1626
+ await page.locator(componentContract.selectors.main).first().waitFor({ state: "visible", timeout: componentReadyTimeoutMs }).catch(() => {
1626
1627
  });
1627
1628
  }
1628
1629
  const hasSubmenuCapability = componentName === "menu" && !!componentContract.selectors.submenuTrigger ? await page.locator(componentContract.selectors.submenuTrigger).count() > 0 : false;
@@ -1631,7 +1632,42 @@ This usually means:
1631
1632
  let staticFailed = 0;
1632
1633
  let staticWarnings = 0;
1633
1634
  for (const rel of componentContract.relationships || []) {
1635
+ if (strategy && typeof strategy.resetState === "function") {
1636
+ try {
1637
+ await strategy.resetState(page);
1638
+ } catch (err) {
1639
+ warnings.push(`Warning: resetState failed before relationship test: ${err instanceof Error ? err.message : String(err)}`);
1640
+ }
1641
+ }
1634
1642
  const relationshipLevel = normalizeLevel(rel.level);
1643
+ if (Array.isArray(rel.setup) && rel.setup.length > 0) {
1644
+ let isAllowedType2 = function(t) {
1645
+ return allowedTypes.includes(t);
1646
+ };
1647
+ var isAllowedType = isAllowedType2;
1648
+ const actionExecutor = new ActionExecutor(page, componentContract.selectors, actionTimeoutMs);
1649
+ const relDescription = rel.type === "aria-reference" ? `${rel.from}.${rel.attribute} references ${rel.to}` : `${rel.parent} contains ${rel.child}`;
1650
+ const allowedTypes = ["focus", "type", "click", "keypress", "hover"];
1651
+ const toSetupAction = (a) => ({
1652
+ ...a,
1653
+ type: isAllowedType2(a.type) ? a.type : "click"
1654
+ });
1655
+ const setupActions = rel.setup.map(toSetupAction);
1656
+ const setupResult = await runSetupActions(setupActions, actionExecutor, strategy, page, relDescription, ["submenu", "submenuTrigger", "submenuItems"]);
1657
+ if (setupResult.skip) {
1658
+ skipped.push(setupResult.message || "Setup action skipped");
1659
+ reporter.reportStaticTest(relDescription, "skip", setupResult.message, relationshipLevel);
1660
+ continue;
1661
+ }
1662
+ if (!setupResult.success) {
1663
+ const failure = `Relationship setup failed: ${setupResult.error}`;
1664
+ const outcome = classifyFailure(failure, rel.level);
1665
+ if (outcome.status === "fail") staticFailed += 1;
1666
+ if (outcome.status === "warn") staticWarnings += 1;
1667
+ reporter.reportStaticTest(relDescription, outcome.status, outcome.detail, outcome.level);
1668
+ continue;
1669
+ }
1670
+ }
1635
1671
  if (componentName === "menu" && !hasSubmenuCapability) {
1636
1672
  const involvesSubmenu = isSubmenuRelation(rel);
1637
1673
  if (involvesSubmenu) {
@@ -1804,7 +1840,53 @@ This usually means:
1804
1840
  }
1805
1841
  }
1806
1842
  const staticAssertionRunner = new AssertionRunner(page, componentContract.selectors, assertionTimeoutMs);
1843
+ async function runSetupActions(setup, actionExecutor, strategy2, page2, description, skipKeywords = []) {
1844
+ if (!Array.isArray(setup) || setup.length === 0) return { success: true };
1845
+ if (strategy2 && typeof strategy2.resetState === "function") {
1846
+ await strategy2.resetState(page2);
1847
+ }
1848
+ for (const setupAct of setup) {
1849
+ let setupResult = { success: true };
1850
+ try {
1851
+ if (setupAct.type === "focus") {
1852
+ if (setupAct.target === "relative" && setupAct.relativeTarget) {
1853
+ setupResult = await actionExecutor.focus("relative", setupAct.relativeTarget);
1854
+ } else {
1855
+ setupResult = await actionExecutor.focus(setupAct.target);
1856
+ }
1857
+ } else if (setupAct.type === "type" && setupAct.value) {
1858
+ setupResult = await actionExecutor.type(setupAct.target, setupAct.value);
1859
+ } else if (setupAct.type === "click") {
1860
+ setupResult = await actionExecutor.click(setupAct.target, setupAct.relativeTarget);
1861
+ } else if (setupAct.type === "keypress" && setupAct.key) {
1862
+ setupResult = await actionExecutor.keypress(setupAct.target, setupAct.key);
1863
+ } else if (setupAct.type === "hover") {
1864
+ setupResult = await actionExecutor.hover(setupAct.target, setupAct.relativeTarget);
1865
+ } else {
1866
+ continue;
1867
+ }
1868
+ } catch (err) {
1869
+ setupResult = { success: false, error: err instanceof Error ? err.message : String(err) };
1870
+ }
1871
+ if (!setupResult.success) {
1872
+ const setupMsg = setupResult.error || "Setup action failed";
1873
+ const isSkip = skipKeywords.some((kw) => description.includes(kw) || setupMsg.includes(kw));
1874
+ if (isSkip) {
1875
+ return { success: false, skip: true, message: `Skipping test - capability not present: ${setupMsg}` };
1876
+ }
1877
+ return { success: false, error: setupMsg };
1878
+ }
1879
+ }
1880
+ return { success: true };
1881
+ }
1807
1882
  for (const test of componentContract.static[0]?.assertions || []) {
1883
+ if (strategy && typeof strategy.resetState === "function") {
1884
+ try {
1885
+ await strategy.resetState(page);
1886
+ } catch (err) {
1887
+ warnings.push(`Warning: resetState failed before static test: ${err instanceof Error ? err.message : String(err)}`);
1888
+ }
1889
+ }
1808
1890
  if (test.target === "relative") continue;
1809
1891
  const staticDescription = `${test.target}${test.attribute ? ` (${test.attribute})` : ""}`;
1810
1892
  const staticLevel = normalizeLevel(test.level);
@@ -1814,6 +1896,33 @@ This usually means:
1814
1896
  reporter.reportStaticTest(staticDescription, "skip", skipMessage, staticLevel);
1815
1897
  continue;
1816
1898
  }
1899
+ if (Array.isArray(test.setup) && test.setup.length > 0) {
1900
+ let isAllowedType2 = function(t) {
1901
+ return allowedTypes.includes(t);
1902
+ };
1903
+ var isAllowedType = isAllowedType2;
1904
+ const actionExecutor = new ActionExecutor(page, componentContract.selectors, actionTimeoutMs);
1905
+ const allowedTypes = ["focus", "type", "click", "keypress", "hover"];
1906
+ const toSetupAction = (a) => ({
1907
+ ...a,
1908
+ type: isAllowedType2(a.type) ? a.type : "click"
1909
+ });
1910
+ const setupActions = test.setup.map(toSetupAction);
1911
+ const setupResult = await runSetupActions(setupActions, actionExecutor, strategy, page, staticDescription, ["submenu", "submenuTrigger", "submenuItems"]);
1912
+ if (setupResult.skip) {
1913
+ skipped.push(setupResult.message || "Setup action skipped");
1914
+ reporter.reportStaticTest(staticDescription, "skip", setupResult.message, staticLevel);
1915
+ continue;
1916
+ }
1917
+ if (!setupResult.success) {
1918
+ const failure = `Static setup failed: ${setupResult.error}`;
1919
+ const outcome = classifyFailure(failure, test.level);
1920
+ if (outcome.status === "fail") staticFailed += 1;
1921
+ if (outcome.status === "warn") staticWarnings += 1;
1922
+ reporter.reportStaticTest(staticDescription, outcome.status, outcome.detail, outcome.level);
1923
+ continue;
1924
+ }
1925
+ }
1817
1926
  const targetSelector = componentContract.selectors[test.target];
1818
1927
  if (!targetSelector) {
1819
1928
  const failure = `Selector for target ${test.target} not found.`;
@@ -1940,31 +2049,26 @@ This usually means:
1940
2049
  const dynamicLevel = normalizeLevel(dynamicTest.level);
1941
2050
  const actionExecutor = new ActionExecutor(page, componentContract.selectors, actionTimeoutMs);
1942
2051
  if (Array.isArray(setup) && setup.length > 0) {
1943
- for (const setupAct of setup) {
1944
- let setupResult;
1945
- if (setupAct.type === "focus") {
1946
- if (setupAct.target === "relative" && setupAct.relativeTarget) {
1947
- setupResult = await actionExecutor.focus("relative", setupAct.relativeTarget);
1948
- } else {
1949
- setupResult = await actionExecutor.focus(setupAct.target);
1950
- }
1951
- } else if (setupAct.type === "type" && setupAct.value) {
1952
- setupResult = await actionExecutor.type(setupAct.target, setupAct.value);
1953
- } else if (setupAct.type === "click") {
1954
- setupResult = await actionExecutor.click(setupAct.target, setupAct.relativeTarget);
1955
- } else if (setupAct.type === "keypress" && setupAct.key) {
1956
- setupResult = await actionExecutor.keypress(setupAct.target, setupAct.key);
1957
- } else if (setupAct.type === "hover") {
1958
- setupResult = await actionExecutor.hover(setupAct.target, setupAct.relativeTarget);
1959
- } else {
1960
- continue;
1961
- }
1962
- if (!setupResult.success) {
1963
- const setupMsg = setupResult.error || "Setup action failed";
1964
- const outcome = classifyFailure(`Setup failed: ${setupMsg}`, dynamicTest.level);
1965
- reporter.reportTest({ description: dynamicTest.description, level: dynamicLevel }, outcome.status, outcome.detail);
1966
- continue;
1967
- }
2052
+ let isAllowedType2 = function(t) {
2053
+ return allowedTypes.includes(t);
2054
+ };
2055
+ var isAllowedType = isAllowedType2;
2056
+ const allowedTypes = ["focus", "type", "click", "keypress", "hover"];
2057
+ const toSetupAction = (a) => ({
2058
+ ...a,
2059
+ type: isAllowedType2(a.type) ? a.type : "click"
2060
+ });
2061
+ const setupActions = setup.map(toSetupAction);
2062
+ const setupResult = await runSetupActions(setupActions, actionExecutor, strategy, page, dynamicTest.description, ["submenu", "submenuTrigger", "submenuItems"]);
2063
+ if (setupResult.skip) {
2064
+ skipped.push(setupResult.message || "Setup action skipped");
2065
+ reporter.reportTest({ description: dynamicTest.description, level: dynamicLevel }, "skip", setupResult.message);
2066
+ continue;
2067
+ }
2068
+ if (!setupResult.success) {
2069
+ const outcome = classifyFailure(`Setup failed: ${setupResult.error}`, dynamicTest.level);
2070
+ reporter.reportTest({ description: dynamicTest.description, level: dynamicLevel }, outcome.status, outcome.detail);
2071
+ continue;
1968
2072
  }
1969
2073
  }
1970
2074
  const failuresBeforeTest = failures.length;
@@ -228,7 +228,7 @@ Error: ${error instanceof Error ? error.message : String(error)}`
228
228
  const devServerUrl = await checkDevServer(url);
229
229
  if (devServerUrl) {
230
230
  console.log(`\u{1F3AD} Running Playwright tests on ${devServerUrl}`);
231
- const { runContractTestsPlaywright } = await import('./contractTestRunnerPlaywright-5FT6K2WN.js');
231
+ const { runContractTestsPlaywright } = await import('./contractTestRunnerPlaywright-5FIGA5G4.js');
232
232
  contract = await runContractTestsPlaywright(componentName, devServerUrl, strictness, config, configBaseDir);
233
233
  } else {
234
234
  throw new Error(
@@ -240,7 +240,7 @@ Error: ${error instanceof Error ? error.message : String(error)}`
240
240
  const devServerUrl = await checkDevServer(url);
241
241
  if (devServerUrl) {
242
242
  console.log(`\u{1F3AD} Running Playwright tests on ${devServerUrl}`);
243
- const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-H24LQ45R.js");
243
+ const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-B2HLZKKK.js");
244
244
  contract = await runContractTestsPlaywright(componentName, devServerUrl, strictness, config, configBaseDir);
245
245
  } else {
246
246
  throw new Error(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aria-ease",
3
- "version": "6.12.1",
3
+ "version": "6.14.0",
4
4
  "description": "Accessibility infrastructure for the entire frontend engineering lifecycle. Build accessible patterns, run automated audits, verify component interactions, and gate deployments — all in one system.",
5
5
  "main": "dist/index.cjs",
6
6
  "type": "module",