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.
- package/README.md +2 -2
- package/dist/{ComboboxComponentStrategy-OGRVZXAF.js → ComboboxComponentStrategy-DU342VMB.js} +7 -7
- package/dist/RelativeTargetResolver-DJAITO6D.js +7 -0
- package/dist/{audit-RM6TCZ5C.js → audit-JYEPKLHR.js} +5 -0
- package/dist/{chunk-FZ7GMIJB.js → chunk-4DU5Z5BR.js} +0 -2
- package/dist/chunk-GLT43UVH.js +43 -0
- package/dist/cli.cjs +138 -28
- package/dist/cli.js +3 -3
- package/dist/{contractTestRunnerPlaywright-EWAWQVHT.js → contractTestRunnerPlaywright-47DCBO4A.js} +126 -60
- package/dist/{contractTestRunnerPlaywright-DIXP5DQ3.js → contractTestRunnerPlaywright-UJKXRXBS.js} +126 -60
- package/dist/index.cjs +256 -53
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +126 -28
- package/dist/src/combobox/index.cjs +4 -0
- package/dist/src/combobox/index.js +4 -0
- package/dist/src/utils/test/{ComboboxComponentStrategy-5AECQSRN.js → ComboboxComponentStrategy-XKQ72RFD.js} +7 -7
- package/dist/src/utils/test/RelativeTargetResolver-G2XDN2VV.js +1 -0
- package/dist/src/utils/test/{chunk-FZ7GMIJB.js → chunk-4DU5Z5BR.js} +0 -2
- package/dist/src/utils/test/chunk-GLT43UVH.js +41 -0
- package/dist/src/utils/test/{contractTestRunnerPlaywright-CIZOXYRW.js → contractTestRunnerPlaywright-AZ4QKLYT.js} +124 -60
- package/dist/src/utils/test/dsl/index.cjs +119 -25
- package/dist/src/utils/test/dsl/index.d.cts +1 -1
- package/dist/src/utils/test/dsl/index.d.ts +1 -1
- package/dist/src/utils/test/dsl/index.js +119 -25
- package/dist/src/utils/test/index.cjs +133 -28
- package/dist/src/utils/test/index.js +3 -3
- package/dist/{test-HBPCSYH5.js → test-6Y4CIQOM.js} +3 -3
- 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-
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
1577
|
+
"main.notFocused": {
|
|
1563
1578
|
setup: [
|
|
1564
1579
|
{
|
|
1565
1580
|
when: ["keyboard"],
|
|
1566
1581
|
steps: () => [
|
|
1567
|
-
|
|
1582
|
+
//what to do here?
|
|
1568
1583
|
]
|
|
1569
1584
|
}
|
|
1570
1585
|
],
|
|
1571
|
-
assertion:
|
|
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: ["
|
|
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:
|
|
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: ["
|
|
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: ["
|
|
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: "
|
|
1682
|
+
target: "popup",
|
|
1637
1683
|
assertion: "toBeVisible",
|
|
1638
|
-
failureMessage: "Expected
|
|
1684
|
+
failureMessage: "Expected popup to be visible"
|
|
1639
1685
|
},
|
|
1640
1686
|
{
|
|
1641
|
-
target: "
|
|
1687
|
+
target: "main",
|
|
1642
1688
|
assertion: "toHaveAttribute",
|
|
1643
1689
|
attribute: "aria-expanded",
|
|
1644
1690
|
expectedValue: "true",
|
|
1645
|
-
failureMessage: "Expect combobox
|
|
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: "
|
|
1698
|
+
target: "popup",
|
|
1653
1699
|
assertion: "notToBeVisible",
|
|
1654
|
-
failureMessage: "Expected
|
|
1700
|
+
failureMessage: "Expected popup to be closed"
|
|
1655
1701
|
},
|
|
1656
1702
|
{
|
|
1657
|
-
target: "
|
|
1703
|
+
target: "main",
|
|
1658
1704
|
assertion: "toHaveAttribute",
|
|
1659
1705
|
attribute: "aria-expanded",
|
|
1660
1706
|
expectedValue: "false",
|
|
1661
|
-
failureMessage: "Expect combobox
|
|
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: "
|
|
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
|
|
1767
|
+
function isMainFocused() {
|
|
1689
1768
|
return [
|
|
1690
1769
|
{
|
|
1691
|
-
target: "
|
|
1770
|
+
target: "main",
|
|
1692
1771
|
assertion: "toHaveFocus",
|
|
1693
|
-
failureMessage: "Expected
|
|
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-
|
|
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
|
|
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
|
-
|
|
28
|
+
popupClosed = await expect(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
29
29
|
}
|
|
30
|
-
if (!
|
|
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
|
-
|
|
33
|
+
popupClosed = await expect(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
34
34
|
}
|
|
35
|
-
if (!
|
|
35
|
+
if (!popupClosed) {
|
|
36
36
|
await page.mouse.click(10, 10);
|
|
37
|
-
|
|
37
|
+
popupClosed = await expect(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
38
38
|
}
|
|
39
|
-
if (!
|
|
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 };
|