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/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  normalizeLevel,
5
5
  normalizeStrictness,
6
6
  resolveEnforcement
7
- } from "./chunk-FZ7GMIJB.js";
7
+ } from "./chunk-4DU5Z5BR.js";
8
8
  import "./chunk-I2KLQ2HA.js";
9
9
 
10
10
  // src/accordion/src/makeAccordionAccessible/makeAccordionAccessible.ts
@@ -1117,6 +1117,7 @@ function makeComboboxAccessible({ comboboxInputId, comboboxButtonId, listBoxId,
1117
1117
  } else if (comboboxInput.value) {
1118
1118
  event.preventDefault();
1119
1119
  comboboxInput.value = "";
1120
+ comboboxInput.setAttribute("aria-activedescendant", "");
1120
1121
  const visibleItems2 = getVisibleItems();
1121
1122
  visibleItems2.forEach((item) => {
1122
1123
  if (item.getAttribute("aria-selected") === "true") item.setAttribute("aria-selected", "false");
@@ -1143,6 +1144,9 @@ function makeComboboxAccessible({ comboboxInputId, comboboxButtonId, listBoxId,
1143
1144
  }
1144
1145
  break;
1145
1146
  case "Tab":
1147
+ if (isOpen && activeIndex >= 0 && activeIndex < visibleItems.length) {
1148
+ selectOption(visibleItems[activeIndex]);
1149
+ }
1146
1150
  if (isOpen) {
1147
1151
  closeListbox();
1148
1152
  }
@@ -1525,7 +1529,7 @@ function resolveSetup(setup, ctx) {
1525
1529
  );
1526
1530
  }
1527
1531
  var COMBOBOX_STATES = {
1528
- "listbox.open": {
1532
+ "popup.open": {
1529
1533
  setup: [
1530
1534
  {
1531
1535
  when: ["keyboard", "textInput"],
@@ -1542,7 +1546,7 @@ var COMBOBOX_STATES = {
1542
1546
  ],
1543
1547
  assertion: isComboboxOpen
1544
1548
  },
1545
- "listbox.closed": {
1549
+ "popup.closed": {
1546
1550
  setup: [
1547
1551
  {
1548
1552
  when: ["keyboard"],
@@ -1557,18 +1561,29 @@ var COMBOBOX_STATES = {
1557
1561
  ]
1558
1562
  }
1559
1563
  ],
1560
- assertion: isComboboxClosed
1564
+ assertion: [...isComboboxClosed(), ...isActiveDescendantEmpty()]
1565
+ },
1566
+ "main.focused": {
1567
+ setup: [
1568
+ {
1569
+ when: ["keyboard"],
1570
+ steps: () => [
1571
+ { type: "focus", target: "main" }
1572
+ ]
1573
+ }
1574
+ ],
1575
+ assertion: isMainFocused
1561
1576
  },
1562
- "input.focused": {
1577
+ "main.notFocused": {
1563
1578
  setup: [
1564
1579
  {
1565
1580
  when: ["keyboard"],
1566
1581
  steps: () => [
1567
- { type: "focus", target: "input" }
1582
+ //what to do here?
1568
1583
  ]
1569
1584
  }
1570
1585
  ],
1571
- assertion: isInputFocused
1586
+ assertion: isMainNotFocused
1572
1587
  },
1573
1588
  "input.filled": {
1574
1589
  setup: [
@@ -1581,8 +1596,19 @@ var COMBOBOX_STATES = {
1581
1596
  ],
1582
1597
  assertion: isInputFilled
1583
1598
  },
1599
+ "input.notFilled": {
1600
+ setup: [
1601
+ {
1602
+ when: ["keyboard", "textInput"],
1603
+ steps: () => [
1604
+ { type: "type", target: "input", value: "" }
1605
+ ]
1606
+ }
1607
+ ],
1608
+ assertion: isInputNotFilled
1609
+ },
1584
1610
  "activeOption.first": {
1585
- requires: ["listbox.open"],
1611
+ requires: ["popup.open"],
1586
1612
  setup: [
1587
1613
  {
1588
1614
  when: ["keyboard"],
@@ -1591,7 +1617,7 @@ var COMBOBOX_STATES = {
1591
1617
  ]
1592
1618
  }
1593
1619
  ],
1594
- assertion: isActiveDescendantNotEmpty
1620
+ assertion: isActiveDescendantFirst
1595
1621
  },
1596
1622
  "activeOption.last": {
1597
1623
  requires: ["activeOption.first"],
@@ -1603,10 +1629,30 @@ var COMBOBOX_STATES = {
1603
1629
  ]
1604
1630
  }
1605
1631
  ],
1632
+ assertion: isActiveDescendantLast
1633
+ },
1634
+ "activeDescendant.notEmpty": {
1635
+ requires: [],
1636
+ setup: [
1637
+ {
1638
+ when: ["keyboard"],
1639
+ steps: () => []
1640
+ }
1641
+ ],
1606
1642
  assertion: isActiveDescendantNotEmpty
1607
1643
  },
1644
+ "activeDescendant.Empty": {
1645
+ requires: [],
1646
+ setup: [
1647
+ {
1648
+ when: ["keyboard"],
1649
+ steps: () => []
1650
+ }
1651
+ ],
1652
+ assertion: isActiveDescendantEmpty
1653
+ },
1608
1654
  "selectedOption.first": {
1609
- requires: ["listbox.open"],
1655
+ requires: ["popup.open"],
1610
1656
  setup: [
1611
1657
  {
1612
1658
  when: ["pointer"],
@@ -1618,7 +1664,7 @@ var COMBOBOX_STATES = {
1618
1664
  assertion: () => isAriaSelected("first")
1619
1665
  },
1620
1666
  "selectedOption.last": {
1621
- requires: ["listbox.open"],
1667
+ requires: ["popup.open"],
1622
1668
  setup: [
1623
1669
  {
1624
1670
  when: ["pointer"],
@@ -1633,43 +1679,76 @@ var COMBOBOX_STATES = {
1633
1679
  function isComboboxOpen() {
1634
1680
  return [
1635
1681
  {
1636
- target: "listbox",
1682
+ target: "popup",
1637
1683
  assertion: "toBeVisible",
1638
- failureMessage: "Expected listbox to be visible"
1684
+ failureMessage: "Expected popup to be visible"
1639
1685
  },
1640
1686
  {
1641
- target: "input",
1687
+ target: "main",
1642
1688
  assertion: "toHaveAttribute",
1643
1689
  attribute: "aria-expanded",
1644
1690
  expectedValue: "true",
1645
- failureMessage: "Expect combobox input to have aria-expanded='true'"
1691
+ failureMessage: "Expect combobox main to have aria-expanded='true'."
1646
1692
  }
1647
1693
  ];
1648
1694
  }
1649
1695
  function isComboboxClosed() {
1650
1696
  return [
1651
1697
  {
1652
- target: "listbox",
1698
+ target: "popup",
1653
1699
  assertion: "notToBeVisible",
1654
- failureMessage: "Expected listbox to be closed"
1700
+ failureMessage: "Expected popup to be closed"
1655
1701
  },
1656
1702
  {
1657
- target: "input",
1703
+ target: "main",
1658
1704
  assertion: "toHaveAttribute",
1659
1705
  attribute: "aria-expanded",
1660
1706
  expectedValue: "false",
1661
- failureMessage: "Expect combobox input to have aria-expanded='false'"
1707
+ failureMessage: "Expect combobox main to have aria-expanded='false'."
1708
+ }
1709
+ ];
1710
+ }
1711
+ function isActiveDescendantFirst() {
1712
+ return [
1713
+ {
1714
+ target: "main",
1715
+ assertion: "toHaveAttribute",
1716
+ attribute: "aria-activedescendant",
1717
+ expectedValue: { ref: "relative", relativeTarget: "first", property: "id" },
1718
+ failureMessage: "Expected aria-activedescendant on main to match the id of the first option."
1719
+ }
1720
+ ];
1721
+ }
1722
+ function isActiveDescendantLast() {
1723
+ return [
1724
+ {
1725
+ target: "main",
1726
+ assertion: "toHaveAttribute",
1727
+ attribute: "aria-activedescendant",
1728
+ expectedValue: { ref: "relative", relativeTarget: "last", property: "id" },
1729
+ failureMessage: "Expected aria-activedescendant on main to match the id of the last option."
1662
1730
  }
1663
1731
  ];
1664
1732
  }
1665
1733
  function isActiveDescendantNotEmpty() {
1666
1734
  return [
1667
1735
  {
1668
- target: "input",
1736
+ target: "main",
1669
1737
  assertion: "toHaveAttribute",
1670
1738
  attribute: "aria-activedescendant",
1671
1739
  expectedValue: "!empty",
1672
- failureMessage: "Expected aria-activedescendant to not be empty"
1740
+ failureMessage: "Expected aria-activedescendant on main to not be empty."
1741
+ }
1742
+ ];
1743
+ }
1744
+ function isActiveDescendantEmpty() {
1745
+ return [
1746
+ {
1747
+ target: "main",
1748
+ assertion: "toHaveAttribute",
1749
+ attribute: "aria-activedescendant",
1750
+ expectedValue: "",
1751
+ failureMessage: "Expected aria-activedescendant on main to be empty."
1673
1752
  }
1674
1753
  ];
1675
1754
  }
@@ -1681,16 +1760,25 @@ function isAriaSelected(index) {
1681
1760
  assertion: "toHaveAttribute",
1682
1761
  attribute: "aria-selected",
1683
1762
  expectedValue: "true",
1684
- failureMessage: `Expected ${index} option to have aria-selected='true'`
1763
+ failureMessage: `Expected ${index} option to have aria-selected='true'.`
1685
1764
  }
1686
1765
  ];
1687
1766
  }
1688
- function isInputFocused() {
1767
+ function isMainFocused() {
1689
1768
  return [
1690
1769
  {
1691
- target: "input",
1770
+ target: "main",
1692
1771
  assertion: "toHaveFocus",
1693
- failureMessage: "Expected input to be focused"
1772
+ failureMessage: "Expected main to be focused."
1773
+ }
1774
+ ];
1775
+ }
1776
+ function isMainNotFocused() {
1777
+ return [
1778
+ {
1779
+ target: "main",
1780
+ assertion: "notToHaveFocus",
1781
+ failureMessage: "Expected main to not have focused."
1694
1782
  }
1695
1783
  ];
1696
1784
  }
@@ -1700,7 +1788,17 @@ function isInputFilled() {
1700
1788
  target: "input",
1701
1789
  assertion: "toHaveValue",
1702
1790
  expectedValue: "test",
1703
- failureMessage: "Expected input to have the value 'test'"
1791
+ failureMessage: "Expected input to have the value 'test'."
1792
+ }
1793
+ ];
1794
+ }
1795
+ function isInputNotFilled() {
1796
+ return [
1797
+ {
1798
+ target: "input",
1799
+ assertion: "toHaveValue",
1800
+ expectedValue: "",
1801
+ failureMessage: "Expected input to have the value ''."
1704
1802
  }
1705
1803
  ];
1706
1804
  }
@@ -2042,7 +2140,7 @@ async function runContractTests(contractPath, componentName, component, strictne
2042
2140
  staticPassed += 1;
2043
2141
  reporter.reportStaticTest(`${test.target} has ${test.attribute}`, "pass", void 0, staticLevel);
2044
2142
  }
2045
- } else if (!attributeValue || !test.expectedValue.split(" | ").includes(attributeValue)) {
2143
+ } else if (!attributeValue || typeof test.expectedValue === "string" && !test.expectedValue.split(" | ").includes(attributeValue)) {
2046
2144
  const outcome = classifyFailure(test.failureMessage + ` Attribute value does not match expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`, test.level);
2047
2145
  if (outcome.status === "fail") staticFailed += 1;
2048
2146
  if (outcome.status === "warn") staticWarnings += 1;
@@ -2129,7 +2227,7 @@ Error: ${error instanceof Error ? error.message : String(error)}`
2129
2227
  const devServerUrl = await checkDevServer(url);
2130
2228
  if (devServerUrl) {
2131
2229
  console.log(`\u{1F3AD} Running Playwright tests on ${devServerUrl}`);
2132
- const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-DIXP5DQ3.js");
2230
+ const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-UJKXRXBS.js");
2133
2231
  contract = await runContractTestsPlaywright(componentName, devServerUrl, strictness, config, configBaseDir);
2134
2232
  } else {
2135
2233
  throw new Error(
@@ -130,6 +130,7 @@ function makeComboboxAccessible({ comboboxInputId, comboboxButtonId, listBoxId,
130
130
  } else if (comboboxInput.value) {
131
131
  event.preventDefault();
132
132
  comboboxInput.value = "";
133
+ comboboxInput.setAttribute("aria-activedescendant", "");
133
134
  const visibleItems2 = getVisibleItems();
134
135
  visibleItems2.forEach((item) => {
135
136
  if (item.getAttribute("aria-selected") === "true") item.setAttribute("aria-selected", "false");
@@ -156,6 +157,9 @@ function makeComboboxAccessible({ comboboxInputId, comboboxButtonId, listBoxId,
156
157
  }
157
158
  break;
158
159
  case "Tab":
160
+ if (isOpen && activeIndex >= 0 && activeIndex < visibleItems.length) {
161
+ selectOption(visibleItems[activeIndex]);
162
+ }
159
163
  if (isOpen) {
160
164
  closeListbox();
161
165
  }
@@ -128,6 +128,7 @@ function makeComboboxAccessible({ comboboxInputId, comboboxButtonId, listBoxId,
128
128
  } else if (comboboxInput.value) {
129
129
  event.preventDefault();
130
130
  comboboxInput.value = "";
131
+ comboboxInput.setAttribute("aria-activedescendant", "");
131
132
  const visibleItems2 = getVisibleItems();
132
133
  visibleItems2.forEach((item) => {
133
134
  if (item.getAttribute("aria-selected") === "true") item.setAttribute("aria-selected", "false");
@@ -154,6 +155,9 @@ function makeComboboxAccessible({ comboboxInputId, comboboxButtonId, listBoxId,
154
155
  }
155
156
  break;
156
157
  case "Tab":
158
+ if (isOpen && activeIndex >= 0 && activeIndex < visibleItems.length) {
159
+ selectOption(visibleItems[activeIndex]);
160
+ }
157
161
  if (isOpen) {
158
162
  closeListbox();
159
163
  }
@@ -14,7 +14,7 @@ var ComboboxComponentStrategy = class {
14
14
  const popupElement = page.locator(popupSelector).first();
15
15
  const isPopupVisible = await popupElement.isVisible().catch(() => false);
16
16
  if (!isPopupVisible) return;
17
- let listBoxClosed = false;
17
+ let popupClosed = false;
18
18
  let closeSelector = this.selectors.input;
19
19
  if (!closeSelector && this.selectors.focusable) {
20
20
  closeSelector = this.selectors.focusable;
@@ -25,18 +25,18 @@ var ComboboxComponentStrategy = class {
25
25
  const closeElement = page.locator(closeSelector).first();
26
26
  await closeElement.focus();
27
27
  await page.keyboard.press("Escape");
28
- listBoxClosed = await expect(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
28
+ popupClosed = await expect(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
29
29
  }
30
- if (!listBoxClosed && this.selectors.button) {
30
+ if (!popupClosed && this.selectors.button) {
31
31
  const buttonElement = page.locator(this.selectors.button).first();
32
32
  await buttonElement.click({ timeout: this.actionTimeoutMs });
33
- listBoxClosed = await expect(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
33
+ popupClosed = await expect(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
34
34
  }
35
- if (!listBoxClosed) {
35
+ if (!popupClosed) {
36
36
  await page.mouse.click(10, 10);
37
- listBoxClosed = await expect(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
37
+ popupClosed = await expect(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
38
38
  }
39
- if (!listBoxClosed) {
39
+ if (!popupClosed) {
40
40
  throw new Error(
41
41
  `\u274C FATAL: Cannot close combobox popup between tests. Popup remains visible after trying:
42
42
  1. Escape key
@@ -0,0 +1 @@
1
+ export { RelativeTargetResolver } from './chunk-GLT43UVH.js';
@@ -308,9 +308,7 @@ async function getOrCreateContext() {
308
308
  if (!sharedContext) {
309
309
  const browser = await getOrCreateBrowser();
310
310
  sharedContext = await browser.newContext({
311
- // Isolated context - no permissions, no geolocation, etc.
312
311
  permissions: [],
313
- // Ignore HTTPS errors for local dev servers
314
312
  ignoreHTTPSErrors: true
315
313
  });
316
314
  }
@@ -0,0 +1,41 @@
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 { RelativeTargetResolver };