aria-ease 6.12.0 → 6.12.1
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 +121 -21
- package/dist/cli.js +3 -3
- package/dist/{contractTestRunnerPlaywright-EWAWQVHT.js → contractTestRunnerPlaywright-H24LQ45R.js} +109 -53
- package/dist/{contractTestRunnerPlaywright-DIXP5DQ3.js → contractTestRunnerPlaywright-NL3JNJYH.js} +109 -53
- package/dist/index.cjs +216 -46
- package/dist/index.js +103 -28
- package/dist/src/combobox/index.cjs +1 -0
- package/dist/src/combobox/index.js +1 -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-5FT6K2WN.js} +107 -53
- package/dist/src/utils/test/dsl/index.cjs +99 -25
- package/dist/src/utils/test/dsl/index.js +99 -25
- package/dist/src/utils/test/index.cjs +116 -21
- package/dist/src/utils/test/index.js +3 -3
- package/dist/{test-HBPCSYH5.js → test-FYSJXQWO.js} +3 -3
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -351,9 +351,7 @@ async function getOrCreateContext() {
|
|
|
351
351
|
if (!sharedContext) {
|
|
352
352
|
const browser = await getOrCreateBrowser();
|
|
353
353
|
sharedContext = await browser.newContext({
|
|
354
|
-
// Isolated context - no permissions, no geolocation, etc.
|
|
355
354
|
permissions: [],
|
|
356
|
-
// Ignore HTTPS errors for local dev servers
|
|
357
355
|
ignoreHTTPSErrors: true
|
|
358
356
|
});
|
|
359
357
|
}
|
|
@@ -740,7 +738,7 @@ var init_ComboboxComponentStrategy = __esm({
|
|
|
740
738
|
const popupElement = page.locator(popupSelector).first();
|
|
741
739
|
const isPopupVisible = await popupElement.isVisible().catch(() => false);
|
|
742
740
|
if (!isPopupVisible) return;
|
|
743
|
-
let
|
|
741
|
+
let popupClosed = false;
|
|
744
742
|
let closeSelector = this.selectors.input;
|
|
745
743
|
if (!closeSelector && this.selectors.focusable) {
|
|
746
744
|
closeSelector = this.selectors.focusable;
|
|
@@ -751,18 +749,18 @@ var init_ComboboxComponentStrategy = __esm({
|
|
|
751
749
|
const closeElement = page.locator(closeSelector).first();
|
|
752
750
|
await closeElement.focus();
|
|
753
751
|
await page.keyboard.press("Escape");
|
|
754
|
-
|
|
752
|
+
popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
755
753
|
}
|
|
756
|
-
if (!
|
|
754
|
+
if (!popupClosed && this.selectors.button) {
|
|
757
755
|
const buttonElement = page.locator(this.selectors.button).first();
|
|
758
756
|
await buttonElement.click({ timeout: this.actionTimeoutMs });
|
|
759
|
-
|
|
757
|
+
popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
760
758
|
}
|
|
761
|
-
if (!
|
|
759
|
+
if (!popupClosed) {
|
|
762
760
|
await page.mouse.click(10, 10);
|
|
763
|
-
|
|
761
|
+
popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
764
762
|
}
|
|
765
|
-
if (!
|
|
763
|
+
if (!popupClosed) {
|
|
766
764
|
throw new Error(
|
|
767
765
|
`\u274C FATAL: Cannot close combobox popup between tests. Popup remains visible after trying:
|
|
768
766
|
1. Escape key
|
|
@@ -982,6 +980,10 @@ var init_ComponentDetector = __esm({
|
|
|
982
980
|
});
|
|
983
981
|
|
|
984
982
|
// src/utils/test/src/RelativeTargetResolver.ts
|
|
983
|
+
var RelativeTargetResolver_exports = {};
|
|
984
|
+
__export(RelativeTargetResolver_exports, {
|
|
985
|
+
RelativeTargetResolver: () => RelativeTargetResolver
|
|
986
|
+
});
|
|
985
987
|
var RelativeTargetResolver;
|
|
986
988
|
var init_RelativeTargetResolver = __esm({
|
|
987
989
|
"src/utils/test/src/RelativeTargetResolver.ts"() {
|
|
@@ -1057,16 +1059,16 @@ var init_ActionExecutor = __esm({
|
|
|
1057
1059
|
async focus(target, relativeTarget, virtualId) {
|
|
1058
1060
|
try {
|
|
1059
1061
|
if (target === "virtual" && virtualId) {
|
|
1060
|
-
const
|
|
1061
|
-
if (!
|
|
1062
|
-
return { success: false, error: `
|
|
1062
|
+
const mainSelector = this.selectors.main;
|
|
1063
|
+
if (!mainSelector) {
|
|
1064
|
+
return { success: false, error: `Main selector not defined for virtual focus.` };
|
|
1063
1065
|
}
|
|
1064
|
-
const
|
|
1065
|
-
const exists = await
|
|
1066
|
+
const main = this.page.locator(mainSelector).first();
|
|
1067
|
+
const exists = await main.count();
|
|
1066
1068
|
if (!exists) {
|
|
1067
|
-
return { success: false, error: `
|
|
1069
|
+
return { success: false, error: `Main element not found for virtual focus.` };
|
|
1068
1070
|
}
|
|
1069
|
-
await
|
|
1071
|
+
await main.evaluate((el, id) => {
|
|
1070
1072
|
el.setAttribute("aria-activedescendant", id);
|
|
1071
1073
|
}, virtualId);
|
|
1072
1074
|
return { success: true };
|
|
@@ -1368,6 +1370,10 @@ var init_AssertionRunner = __esm({
|
|
|
1368
1370
|
};
|
|
1369
1371
|
}
|
|
1370
1372
|
}
|
|
1373
|
+
if (typeof expectedValue !== "string") {
|
|
1374
|
+
console.error("[AssertionRunner] expectedValue is not a string:", expectedValue);
|
|
1375
|
+
throw new Error(`AssertionRunner: expectedValue for attribute assertion must be a string, but got: ${JSON.stringify(expectedValue)}`);
|
|
1376
|
+
}
|
|
1371
1377
|
const expectedValues = expectedValue.split(" | ").map((v) => v.trim());
|
|
1372
1378
|
const attributeValue = await target.getAttribute(attribute);
|
|
1373
1379
|
if (attributeValue !== null && expectedValues.includes(attributeValue)) {
|
|
@@ -1800,6 +1806,52 @@ This usually means:
|
|
|
1800
1806
|
reporter.reportStaticTest(relDescription, "pass", void 0, relationshipLevel);
|
|
1801
1807
|
}
|
|
1802
1808
|
}
|
|
1809
|
+
async function resolveExpectedValue(expectedValue, selectors, page2, context = {}) {
|
|
1810
|
+
if (!expectedValue || typeof expectedValue !== "object" || !("ref" in expectedValue)) return expectedValue;
|
|
1811
|
+
let refSelector;
|
|
1812
|
+
if (expectedValue.ref === "relative") {
|
|
1813
|
+
if (!expectedValue.relativeTarget || !context.relativeBaseSelector) return void 0;
|
|
1814
|
+
const baseLocator = page2.locator(context.relativeBaseSelector);
|
|
1815
|
+
const count = await baseLocator.count();
|
|
1816
|
+
let idx = 0;
|
|
1817
|
+
if (expectedValue.relativeTarget === "first") idx = 0;
|
|
1818
|
+
else if (expectedValue.relativeTarget === "second") idx = 1;
|
|
1819
|
+
else if (expectedValue.relativeTarget === "last") idx = count - 1;
|
|
1820
|
+
else if (!isNaN(Number(expectedValue.relativeTarget))) idx = Number(expectedValue.relativeTarget);
|
|
1821
|
+
else idx = 0;
|
|
1822
|
+
if (idx < 0 || idx >= count) return void 0;
|
|
1823
|
+
const relElem = baseLocator.nth(idx);
|
|
1824
|
+
return await getPropertyFromLocator(relElem, expectedValue.property || expectedValue.attribute);
|
|
1825
|
+
} else {
|
|
1826
|
+
refSelector = selectors[expectedValue.ref];
|
|
1827
|
+
if (!refSelector) throw new Error(`Selector for ref '${expectedValue.ref}' not found in contract selectors.`);
|
|
1828
|
+
const refLocator = page2.locator(refSelector).first();
|
|
1829
|
+
return await getPropertyFromLocator(refLocator, expectedValue.property || expectedValue.attribute);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
async function getPropertyFromLocator(locator, property) {
|
|
1833
|
+
if (!locator) return void 0;
|
|
1834
|
+
if (!property || property === "id") {
|
|
1835
|
+
return await locator.getAttribute("id") ?? void 0;
|
|
1836
|
+
} else if (property === "class") {
|
|
1837
|
+
return await locator.getAttribute("class") ?? void 0;
|
|
1838
|
+
} else if (property === "textContent") {
|
|
1839
|
+
return await locator.evaluate((el) => el.textContent ?? void 0);
|
|
1840
|
+
} else if (property.startsWith("aria-")) {
|
|
1841
|
+
return await locator.getAttribute(property) ?? void 0;
|
|
1842
|
+
} else if (property.endsWith("*")) {
|
|
1843
|
+
const attrs = await locator.evaluate((el) => {
|
|
1844
|
+
const out = [];
|
|
1845
|
+
for (const attr of Array.from(el.attributes)) {
|
|
1846
|
+
if (attr.name.startsWith("aria-")) out.push(`${attr.name}=${attr.value}`);
|
|
1847
|
+
}
|
|
1848
|
+
return out.join(";");
|
|
1849
|
+
});
|
|
1850
|
+
return attrs;
|
|
1851
|
+
} else {
|
|
1852
|
+
return await locator.getAttribute(property) ?? void 0;
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1803
1855
|
const staticAssertionRunner = new AssertionRunner(page, componentContract.selectors, assertionTimeoutMs);
|
|
1804
1856
|
for (const test of componentContract.static[0]?.assertions || []) {
|
|
1805
1857
|
if (test.target === "relative") continue;
|
|
@@ -1842,6 +1894,22 @@ This usually means:
|
|
|
1842
1894
|
}
|
|
1843
1895
|
return false;
|
|
1844
1896
|
};
|
|
1897
|
+
let expectedValue = test.expectedValue;
|
|
1898
|
+
if (test.expectedValue && typeof test.expectedValue === "object" && "ref" in test.expectedValue) {
|
|
1899
|
+
const context = {};
|
|
1900
|
+
const relTarget = test.relativeTarget;
|
|
1901
|
+
if (test.expectedValue.ref === "relative" && test.target === "relative" && relTarget) {
|
|
1902
|
+
const baseSel = componentContract.selectors[relTarget];
|
|
1903
|
+
if (!baseSel) throw new Error(`Selector for relativeTarget '${relTarget}' not found in contract selectors.`);
|
|
1904
|
+
context.relativeBaseSelector = baseSel;
|
|
1905
|
+
} else if (test.expectedValue.ref === "relative" && relTarget) {
|
|
1906
|
+
const baseSel = componentContract.selectors[relTarget];
|
|
1907
|
+
if (!baseSel) throw new Error(`Selector for relativeTarget '${relTarget}' not found in contract selectors.`);
|
|
1908
|
+
context.relativeBaseSelector = baseSel;
|
|
1909
|
+
}
|
|
1910
|
+
expectedValue = await resolveExpectedValue(test.expectedValue, componentContract.selectors, page, context);
|
|
1911
|
+
console.log("Expected value in static check", expectedValue);
|
|
1912
|
+
}
|
|
1845
1913
|
if (!test.expectedValue) {
|
|
1846
1914
|
const attributes = test.attribute.split(" | ");
|
|
1847
1915
|
let hasAny = false;
|
|
@@ -1875,16 +1943,17 @@ This usually means:
|
|
|
1875
1943
|
reporter.reportStaticTest(staticDescription, "pass", void 0, staticLevel);
|
|
1876
1944
|
}
|
|
1877
1945
|
} else {
|
|
1878
|
-
if (isRedundantCheck(targetSelector, test.attribute,
|
|
1879
|
-
passes.push(`${test.attribute}="${
|
|
1946
|
+
if (isRedundantCheck(targetSelector, test.attribute, typeof expectedValue === "string" ? expectedValue : void 0)) {
|
|
1947
|
+
passes.push(`${test.attribute}="${expectedValue}" on ${test.target} verified by selector (already present in: ${targetSelector}).`);
|
|
1880
1948
|
staticPassed += 1;
|
|
1881
1949
|
reporter.reportStaticTest(staticDescription, "pass", void 0, staticLevel);
|
|
1882
1950
|
} else {
|
|
1951
|
+
const valueToCheck = expectedValue ?? "";
|
|
1883
1952
|
const result = await staticAssertionRunner.validateAttribute(
|
|
1884
1953
|
target,
|
|
1885
1954
|
test.target,
|
|
1886
1955
|
test.attribute,
|
|
1887
|
-
|
|
1956
|
+
valueToCheck,
|
|
1888
1957
|
test.failureMessage,
|
|
1889
1958
|
"Static ARIA Test"
|
|
1890
1959
|
);
|
|
@@ -2002,7 +2071,33 @@ This usually means:
|
|
|
2002
2071
|
continue;
|
|
2003
2072
|
}
|
|
2004
2073
|
for (const assertion of assertions) {
|
|
2005
|
-
|
|
2074
|
+
let expectedValue;
|
|
2075
|
+
if (assertion.expectedValue && typeof assertion.expectedValue === "object" && "ref" in assertion.expectedValue) {
|
|
2076
|
+
if (assertion.expectedValue.ref === "relative") {
|
|
2077
|
+
const { RelativeTargetResolver: RelativeTargetResolver2 } = await Promise.resolve().then(() => (init_RelativeTargetResolver(), RelativeTargetResolver_exports));
|
|
2078
|
+
const relativeSelector = componentContract.selectors.relative;
|
|
2079
|
+
if (!relativeSelector) throw new Error("Relative selector not defined in contract selectors.");
|
|
2080
|
+
const relTarget = assertion.relativeTarget || "first";
|
|
2081
|
+
const relElem = await RelativeTargetResolver2.resolve(page, relativeSelector, relTarget);
|
|
2082
|
+
if (!relElem) throw new Error(`Could not resolve relative target '${relTarget}' for expectedValue.`);
|
|
2083
|
+
const prop = assertion.expectedValue.property || assertion.expectedValue.attribute || "id";
|
|
2084
|
+
if (prop === "textContent") {
|
|
2085
|
+
expectedValue = await relElem.evaluate((el) => el.textContent ?? void 0);
|
|
2086
|
+
} else {
|
|
2087
|
+
const attr = await relElem.getAttribute(prop);
|
|
2088
|
+
expectedValue = attr === null ? void 0 : attr;
|
|
2089
|
+
}
|
|
2090
|
+
} else {
|
|
2091
|
+
expectedValue = await resolveExpectedValue(assertion.expectedValue, componentContract.selectors, page, {});
|
|
2092
|
+
}
|
|
2093
|
+
} else if (typeof assertion.expectedValue === "string" || typeof assertion.expectedValue === "undefined") {
|
|
2094
|
+
expectedValue = assertion.expectedValue;
|
|
2095
|
+
} else {
|
|
2096
|
+
expectedValue = "";
|
|
2097
|
+
}
|
|
2098
|
+
const assertionToRun = { ...assertion, expectedValue };
|
|
2099
|
+
const valueToCheck = expectedValue ?? "";
|
|
2100
|
+
const result = await assertionRunner.validate({ ...assertionToRun, expectedValue: valueToCheck }, dynamicTest.description);
|
|
2006
2101
|
if (result.success && result.passMessage) {
|
|
2007
2102
|
passes.push(result.passMessage);
|
|
2008
2103
|
} else if (!result.success && result.failMessage) {
|
|
@@ -3329,6 +3424,7 @@ function makeComboboxAccessible({ comboboxInputId, comboboxButtonId, listBoxId,
|
|
|
3329
3424
|
} else if (comboboxInput.value) {
|
|
3330
3425
|
event.preventDefault();
|
|
3331
3426
|
comboboxInput.value = "";
|
|
3427
|
+
comboboxInput.setAttribute("aria-activedescendant", "");
|
|
3332
3428
|
const visibleItems2 = getVisibleItems();
|
|
3333
3429
|
visibleItems2.forEach((item) => {
|
|
3334
3430
|
if (item.getAttribute("aria-selected") === "true") item.setAttribute("aria-selected", "false");
|
|
@@ -3737,7 +3833,7 @@ function resolveSetup(setup, ctx) {
|
|
|
3737
3833
|
);
|
|
3738
3834
|
}
|
|
3739
3835
|
var COMBOBOX_STATES = {
|
|
3740
|
-
"
|
|
3836
|
+
"popup.open": {
|
|
3741
3837
|
setup: [
|
|
3742
3838
|
{
|
|
3743
3839
|
when: ["keyboard", "textInput"],
|
|
@@ -3754,7 +3850,7 @@ var COMBOBOX_STATES = {
|
|
|
3754
3850
|
],
|
|
3755
3851
|
assertion: isComboboxOpen
|
|
3756
3852
|
},
|
|
3757
|
-
"
|
|
3853
|
+
"popup.closed": {
|
|
3758
3854
|
setup: [
|
|
3759
3855
|
{
|
|
3760
3856
|
when: ["keyboard"],
|
|
@@ -3769,18 +3865,18 @@ var COMBOBOX_STATES = {
|
|
|
3769
3865
|
]
|
|
3770
3866
|
}
|
|
3771
3867
|
],
|
|
3772
|
-
assertion: isComboboxClosed
|
|
3868
|
+
assertion: [...isComboboxClosed(), ...isActiveDescendantEmpty()]
|
|
3773
3869
|
},
|
|
3774
|
-
"
|
|
3870
|
+
"main.focused": {
|
|
3775
3871
|
setup: [
|
|
3776
3872
|
{
|
|
3777
3873
|
when: ["keyboard"],
|
|
3778
3874
|
steps: () => [
|
|
3779
|
-
{ type: "focus", target: "
|
|
3875
|
+
{ type: "focus", target: "main" }
|
|
3780
3876
|
]
|
|
3781
3877
|
}
|
|
3782
3878
|
],
|
|
3783
|
-
assertion:
|
|
3879
|
+
assertion: isMainFocused
|
|
3784
3880
|
},
|
|
3785
3881
|
"input.filled": {
|
|
3786
3882
|
setup: [
|
|
@@ -3793,8 +3889,19 @@ var COMBOBOX_STATES = {
|
|
|
3793
3889
|
],
|
|
3794
3890
|
assertion: isInputFilled
|
|
3795
3891
|
},
|
|
3892
|
+
"input.notFilled": {
|
|
3893
|
+
setup: [
|
|
3894
|
+
{
|
|
3895
|
+
when: ["keyboard", "textInput"],
|
|
3896
|
+
steps: () => [
|
|
3897
|
+
{ type: "type", target: "input", value: "" }
|
|
3898
|
+
]
|
|
3899
|
+
}
|
|
3900
|
+
],
|
|
3901
|
+
assertion: isInputNotFilled
|
|
3902
|
+
},
|
|
3796
3903
|
"activeOption.first": {
|
|
3797
|
-
requires: ["
|
|
3904
|
+
requires: ["popup.open"],
|
|
3798
3905
|
setup: [
|
|
3799
3906
|
{
|
|
3800
3907
|
when: ["keyboard"],
|
|
@@ -3803,7 +3910,7 @@ var COMBOBOX_STATES = {
|
|
|
3803
3910
|
]
|
|
3804
3911
|
}
|
|
3805
3912
|
],
|
|
3806
|
-
assertion:
|
|
3913
|
+
assertion: isActiveDescendantFirst
|
|
3807
3914
|
},
|
|
3808
3915
|
"activeOption.last": {
|
|
3809
3916
|
requires: ["activeOption.first"],
|
|
@@ -3815,10 +3922,30 @@ var COMBOBOX_STATES = {
|
|
|
3815
3922
|
]
|
|
3816
3923
|
}
|
|
3817
3924
|
],
|
|
3925
|
+
assertion: isActiveDescendantLast
|
|
3926
|
+
},
|
|
3927
|
+
"activeDescendant.notEmpty": {
|
|
3928
|
+
requires: [],
|
|
3929
|
+
setup: [
|
|
3930
|
+
{
|
|
3931
|
+
when: ["keyboard"],
|
|
3932
|
+
steps: () => []
|
|
3933
|
+
}
|
|
3934
|
+
],
|
|
3818
3935
|
assertion: isActiveDescendantNotEmpty
|
|
3819
3936
|
},
|
|
3937
|
+
"activeDescendant.Empty": {
|
|
3938
|
+
requires: [],
|
|
3939
|
+
setup: [
|
|
3940
|
+
{
|
|
3941
|
+
when: ["keyboard"],
|
|
3942
|
+
steps: () => []
|
|
3943
|
+
}
|
|
3944
|
+
],
|
|
3945
|
+
assertion: isActiveDescendantEmpty
|
|
3946
|
+
},
|
|
3820
3947
|
"selectedOption.first": {
|
|
3821
|
-
requires: ["
|
|
3948
|
+
requires: ["popup.open"],
|
|
3822
3949
|
setup: [
|
|
3823
3950
|
{
|
|
3824
3951
|
when: ["pointer"],
|
|
@@ -3830,7 +3957,7 @@ var COMBOBOX_STATES = {
|
|
|
3830
3957
|
assertion: () => isAriaSelected("first")
|
|
3831
3958
|
},
|
|
3832
3959
|
"selectedOption.last": {
|
|
3833
|
-
requires: ["
|
|
3960
|
+
requires: ["popup.open"],
|
|
3834
3961
|
setup: [
|
|
3835
3962
|
{
|
|
3836
3963
|
when: ["pointer"],
|
|
@@ -3845,43 +3972,76 @@ var COMBOBOX_STATES = {
|
|
|
3845
3972
|
function isComboboxOpen() {
|
|
3846
3973
|
return [
|
|
3847
3974
|
{
|
|
3848
|
-
target: "
|
|
3975
|
+
target: "popup",
|
|
3849
3976
|
assertion: "toBeVisible",
|
|
3850
|
-
failureMessage: "Expected
|
|
3977
|
+
failureMessage: "Expected popup to be visible"
|
|
3851
3978
|
},
|
|
3852
3979
|
{
|
|
3853
|
-
target: "
|
|
3980
|
+
target: "main",
|
|
3854
3981
|
assertion: "toHaveAttribute",
|
|
3855
3982
|
attribute: "aria-expanded",
|
|
3856
3983
|
expectedValue: "true",
|
|
3857
|
-
failureMessage: "Expect combobox
|
|
3984
|
+
failureMessage: "Expect combobox main to have aria-expanded='true'."
|
|
3858
3985
|
}
|
|
3859
3986
|
];
|
|
3860
3987
|
}
|
|
3861
3988
|
function isComboboxClosed() {
|
|
3862
3989
|
return [
|
|
3863
3990
|
{
|
|
3864
|
-
target: "
|
|
3991
|
+
target: "popup",
|
|
3865
3992
|
assertion: "notToBeVisible",
|
|
3866
|
-
failureMessage: "Expected
|
|
3993
|
+
failureMessage: "Expected popup to be closed"
|
|
3867
3994
|
},
|
|
3868
3995
|
{
|
|
3869
|
-
target: "
|
|
3996
|
+
target: "main",
|
|
3870
3997
|
assertion: "toHaveAttribute",
|
|
3871
3998
|
attribute: "aria-expanded",
|
|
3872
3999
|
expectedValue: "false",
|
|
3873
|
-
failureMessage: "Expect combobox
|
|
4000
|
+
failureMessage: "Expect combobox main to have aria-expanded='false'."
|
|
4001
|
+
}
|
|
4002
|
+
];
|
|
4003
|
+
}
|
|
4004
|
+
function isActiveDescendantFirst() {
|
|
4005
|
+
return [
|
|
4006
|
+
{
|
|
4007
|
+
target: "main",
|
|
4008
|
+
assertion: "toHaveAttribute",
|
|
4009
|
+
attribute: "aria-activedescendant",
|
|
4010
|
+
expectedValue: { ref: "relative", relativeTarget: "first", property: "id" },
|
|
4011
|
+
failureMessage: "Expected aria-activedescendant on main to match the id of the first option."
|
|
4012
|
+
}
|
|
4013
|
+
];
|
|
4014
|
+
}
|
|
4015
|
+
function isActiveDescendantLast() {
|
|
4016
|
+
return [
|
|
4017
|
+
{
|
|
4018
|
+
target: "main",
|
|
4019
|
+
assertion: "toHaveAttribute",
|
|
4020
|
+
attribute: "aria-activedescendant",
|
|
4021
|
+
expectedValue: { ref: "relative", relativeTarget: "last", property: "id" },
|
|
4022
|
+
failureMessage: "Expected aria-activedescendant on main to match the id of the last option."
|
|
3874
4023
|
}
|
|
3875
4024
|
];
|
|
3876
4025
|
}
|
|
3877
4026
|
function isActiveDescendantNotEmpty() {
|
|
3878
4027
|
return [
|
|
3879
4028
|
{
|
|
3880
|
-
target: "
|
|
4029
|
+
target: "main",
|
|
3881
4030
|
assertion: "toHaveAttribute",
|
|
3882
4031
|
attribute: "aria-activedescendant",
|
|
3883
4032
|
expectedValue: "!empty",
|
|
3884
|
-
failureMessage: "Expected aria-activedescendant to not be empty"
|
|
4033
|
+
failureMessage: "Expected aria-activedescendant on main to not be empty."
|
|
4034
|
+
}
|
|
4035
|
+
];
|
|
4036
|
+
}
|
|
4037
|
+
function isActiveDescendantEmpty() {
|
|
4038
|
+
return [
|
|
4039
|
+
{
|
|
4040
|
+
target: "main",
|
|
4041
|
+
assertion: "toHaveAttribute",
|
|
4042
|
+
attribute: "aria-activedescendant",
|
|
4043
|
+
expectedValue: "",
|
|
4044
|
+
failureMessage: "Expected aria-activedescendant on main to be empty."
|
|
3885
4045
|
}
|
|
3886
4046
|
];
|
|
3887
4047
|
}
|
|
@@ -3893,16 +4053,16 @@ function isAriaSelected(index) {
|
|
|
3893
4053
|
assertion: "toHaveAttribute",
|
|
3894
4054
|
attribute: "aria-selected",
|
|
3895
4055
|
expectedValue: "true",
|
|
3896
|
-
failureMessage: `Expected ${index} option to have aria-selected='true'
|
|
4056
|
+
failureMessage: `Expected ${index} option to have aria-selected='true'.`
|
|
3897
4057
|
}
|
|
3898
4058
|
];
|
|
3899
4059
|
}
|
|
3900
|
-
function
|
|
4060
|
+
function isMainFocused() {
|
|
3901
4061
|
return [
|
|
3902
4062
|
{
|
|
3903
|
-
target: "
|
|
4063
|
+
target: "main",
|
|
3904
4064
|
assertion: "toHaveFocus",
|
|
3905
|
-
failureMessage: "Expected
|
|
4065
|
+
failureMessage: "Expected main to be focused."
|
|
3906
4066
|
}
|
|
3907
4067
|
];
|
|
3908
4068
|
}
|
|
@@ -3912,7 +4072,17 @@ function isInputFilled() {
|
|
|
3912
4072
|
target: "input",
|
|
3913
4073
|
assertion: "toHaveValue",
|
|
3914
4074
|
expectedValue: "test",
|
|
3915
|
-
failureMessage: "Expected input to have the value 'test'"
|
|
4075
|
+
failureMessage: "Expected input to have the value 'test'."
|
|
4076
|
+
}
|
|
4077
|
+
];
|
|
4078
|
+
}
|
|
4079
|
+
function isInputNotFilled() {
|
|
4080
|
+
return [
|
|
4081
|
+
{
|
|
4082
|
+
target: "input",
|
|
4083
|
+
assertion: "toHaveValue",
|
|
4084
|
+
expectedValue: "",
|
|
4085
|
+
failureMessage: "Expected input to have the value ''."
|
|
3916
4086
|
}
|
|
3917
4087
|
];
|
|
3918
4088
|
}
|
|
@@ -4256,7 +4426,7 @@ async function runContractTests(contractPath, componentName, component, strictne
|
|
|
4256
4426
|
staticPassed += 1;
|
|
4257
4427
|
reporter.reportStaticTest(`${test.target} has ${test.attribute}`, "pass", void 0, staticLevel);
|
|
4258
4428
|
}
|
|
4259
|
-
} else if (!attributeValue || !test.expectedValue.split(" | ").includes(attributeValue)) {
|
|
4429
|
+
} else if (!attributeValue || typeof test.expectedValue === "string" && !test.expectedValue.split(" | ").includes(attributeValue)) {
|
|
4260
4430
|
const outcome = classifyFailure(test.failureMessage + ` Attribute value does not match expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`, test.level);
|
|
4261
4431
|
if (outcome.status === "fail") staticFailed += 1;
|
|
4262
4432
|
if (outcome.status === "warn") staticWarnings += 1;
|