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/README.md
CHANGED
|
@@ -1000,7 +1000,7 @@ export default {
|
|
|
1000
1000
|
audit: {
|
|
1001
1001
|
urls: [
|
|
1002
1002
|
"http://localhost:5173", // Homepage
|
|
1003
|
-
"http://localhost:5173/
|
|
1003
|
+
"http://localhost:5173/getting-started", // Docs
|
|
1004
1004
|
"http://localhost:5173/examples", // Examples
|
|
1005
1005
|
],
|
|
1006
1006
|
output: {
|
|
@@ -1130,7 +1130,7 @@ You've shifted accessibility left (into development), automated the verification
|
|
|
1130
1130
|
|
|
1131
1131
|
## 📖 More Resources
|
|
1132
1132
|
|
|
1133
|
-
- [Full Documentation](https://ariaease.site/
|
|
1133
|
+
- [Full Documentation](https://ariaease.site/getting-started)
|
|
1134
1134
|
- [GitHub Repository](https://github.com/aria-ease/aria-ease)
|
|
1135
1135
|
- [Report Issues](https://github.com/aria-ease/aria-ease/issues)
|
|
1136
1136
|
- [Contributing Guide](https://github.com/aria-ease/aria-ease/blob/main/CONTRIBUTION-GUIDELINES.md)
|
package/dist/{ComboboxComponentStrategy-OGRVZXAF.js → ComboboxComponentStrategy-DU342VMB.js}
RENAMED
|
@@ -17,7 +17,7 @@ var ComboboxComponentStrategy = class {
|
|
|
17
17
|
const popupElement = page.locator(popupSelector).first();
|
|
18
18
|
const isPopupVisible = await popupElement.isVisible().catch(() => false);
|
|
19
19
|
if (!isPopupVisible) return;
|
|
20
|
-
let
|
|
20
|
+
let popupClosed = false;
|
|
21
21
|
let closeSelector = this.selectors.input;
|
|
22
22
|
if (!closeSelector && this.selectors.focusable) {
|
|
23
23
|
closeSelector = this.selectors.focusable;
|
|
@@ -28,18 +28,18 @@ var ComboboxComponentStrategy = class {
|
|
|
28
28
|
const closeElement = page.locator(closeSelector).first();
|
|
29
29
|
await closeElement.focus();
|
|
30
30
|
await page.keyboard.press("Escape");
|
|
31
|
-
|
|
31
|
+
popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
32
32
|
}
|
|
33
|
-
if (!
|
|
33
|
+
if (!popupClosed && this.selectors.button) {
|
|
34
34
|
const buttonElement = page.locator(this.selectors.button).first();
|
|
35
35
|
await buttonElement.click({ timeout: this.actionTimeoutMs });
|
|
36
|
-
|
|
36
|
+
popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
37
37
|
}
|
|
38
|
-
if (!
|
|
38
|
+
if (!popupClosed) {
|
|
39
39
|
await page.mouse.click(10, 10);
|
|
40
|
-
|
|
40
|
+
popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
41
41
|
}
|
|
42
|
-
if (!
|
|
42
|
+
if (!popupClosed) {
|
|
43
43
|
throw new Error(
|
|
44
44
|
`\u274C FATAL: Cannot close combobox popup between tests. Popup remains visible after trying:
|
|
45
45
|
1. Escape key
|
|
@@ -19,6 +19,11 @@ async function runAudit(url, options) {
|
|
|
19
19
|
const context = await browser.newContext();
|
|
20
20
|
const page = await context.newPage();
|
|
21
21
|
await page.goto(url, { waitUntil, timeout });
|
|
22
|
+
try {
|
|
23
|
+
await page.waitForSelector("main", { state: "visible", timeout });
|
|
24
|
+
} catch (waitError) {
|
|
25
|
+
console.warn(`\u26A0\uFE0F Warning: <main> landmark not found or not visible on ${url} after ${timeout}ms. Audit will continue, but results may be inaccurate. Consider adding a <main> element to improve audit accuracy. ${waitError instanceof Error ? waitError.message : String(waitError)}`);
|
|
26
|
+
}
|
|
22
27
|
const axe = new AxeBuilder({ page });
|
|
23
28
|
const axeResults = await axe.analyze();
|
|
24
29
|
await page.close();
|
|
@@ -309,9 +309,7 @@ async function getOrCreateContext() {
|
|
|
309
309
|
if (!sharedContext) {
|
|
310
310
|
const browser = await getOrCreateBrowser();
|
|
311
311
|
sharedContext = await browser.newContext({
|
|
312
|
-
// Isolated context - no permissions, no geolocation, etc.
|
|
313
312
|
permissions: [],
|
|
314
|
-
// Ignore HTTPS errors for local dev servers
|
|
315
313
|
ignoreHTTPSErrors: true
|
|
316
314
|
});
|
|
317
315
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
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 {
|
|
42
|
+
RelativeTargetResolver
|
|
43
|
+
};
|
package/dist/cli.cjs
CHANGED
|
@@ -356,6 +356,11 @@ async function runAudit(url, options) {
|
|
|
356
356
|
const context = await browser.newContext();
|
|
357
357
|
const page = await context.newPage();
|
|
358
358
|
await page.goto(url, { waitUntil, timeout });
|
|
359
|
+
try {
|
|
360
|
+
await page.waitForSelector("main", { state: "visible", timeout });
|
|
361
|
+
} catch (waitError) {
|
|
362
|
+
console.warn(`\u26A0\uFE0F Warning: <main> landmark not found or not visible on ${url} after ${timeout}ms. Audit will continue, but results may be inaccurate. Consider adding a <main> element to improve audit accuracy. ${waitError instanceof Error ? waitError.message : String(waitError)}`);
|
|
363
|
+
}
|
|
359
364
|
const axe2 = new import_playwright.default({ page });
|
|
360
365
|
const axeResults = await axe2.analyze();
|
|
361
366
|
await page.close();
|
|
@@ -1030,7 +1035,7 @@ async function runContractTests(contractPath, componentName, component, strictne
|
|
|
1030
1035
|
staticPassed += 1;
|
|
1031
1036
|
reporter.reportStaticTest(`${test.target} has ${test.attribute}`, "pass", void 0, staticLevel);
|
|
1032
1037
|
}
|
|
1033
|
-
} else if (!attributeValue || !test.expectedValue.split(" | ").includes(attributeValue)) {
|
|
1038
|
+
} else if (!attributeValue || typeof test.expectedValue === "string" && !test.expectedValue.split(" | ").includes(attributeValue)) {
|
|
1034
1039
|
const outcome = classifyFailure(test.failureMessage + ` Attribute value does not match expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`, test.level);
|
|
1035
1040
|
if (outcome.status === "fail") staticFailed += 1;
|
|
1036
1041
|
if (outcome.status === "warn") staticWarnings += 1;
|
|
@@ -1078,9 +1083,7 @@ async function getOrCreateContext() {
|
|
|
1078
1083
|
if (!sharedContext) {
|
|
1079
1084
|
const browser = await getOrCreateBrowser();
|
|
1080
1085
|
sharedContext = await browser.newContext({
|
|
1081
|
-
// Isolated context - no permissions, no geolocation, etc.
|
|
1082
1086
|
permissions: [],
|
|
1083
|
-
// Ignore HTTPS errors for local dev servers
|
|
1084
1087
|
ignoreHTTPSErrors: true
|
|
1085
1088
|
});
|
|
1086
1089
|
}
|
|
@@ -1278,7 +1281,7 @@ var init_ComboboxComponentStrategy = __esm({
|
|
|
1278
1281
|
const popupElement = page.locator(popupSelector).first();
|
|
1279
1282
|
const isPopupVisible = await popupElement.isVisible().catch(() => false);
|
|
1280
1283
|
if (!isPopupVisible) return;
|
|
1281
|
-
let
|
|
1284
|
+
let popupClosed = false;
|
|
1282
1285
|
let closeSelector = this.selectors.input;
|
|
1283
1286
|
if (!closeSelector && this.selectors.focusable) {
|
|
1284
1287
|
closeSelector = this.selectors.focusable;
|
|
@@ -1289,18 +1292,18 @@ var init_ComboboxComponentStrategy = __esm({
|
|
|
1289
1292
|
const closeElement = page.locator(closeSelector).first();
|
|
1290
1293
|
await closeElement.focus();
|
|
1291
1294
|
await page.keyboard.press("Escape");
|
|
1292
|
-
|
|
1295
|
+
popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
1293
1296
|
}
|
|
1294
|
-
if (!
|
|
1297
|
+
if (!popupClosed && this.selectors.button) {
|
|
1295
1298
|
const buttonElement = page.locator(this.selectors.button).first();
|
|
1296
1299
|
await buttonElement.click({ timeout: this.actionTimeoutMs });
|
|
1297
|
-
|
|
1300
|
+
popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
1298
1301
|
}
|
|
1299
|
-
if (!
|
|
1302
|
+
if (!popupClosed) {
|
|
1300
1303
|
await page.mouse.click(10, 10);
|
|
1301
|
-
|
|
1304
|
+
popupClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: this.assertionTimeoutMs }).then(() => true).catch(() => false);
|
|
1302
1305
|
}
|
|
1303
|
-
if (!
|
|
1306
|
+
if (!popupClosed) {
|
|
1304
1307
|
throw new Error(
|
|
1305
1308
|
`\u274C FATAL: Cannot close combobox popup between tests. Popup remains visible after trying:
|
|
1306
1309
|
1. Escape key
|
|
@@ -1520,6 +1523,10 @@ var init_ComponentDetector = __esm({
|
|
|
1520
1523
|
});
|
|
1521
1524
|
|
|
1522
1525
|
// src/utils/test/src/RelativeTargetResolver.ts
|
|
1526
|
+
var RelativeTargetResolver_exports = {};
|
|
1527
|
+
__export(RelativeTargetResolver_exports, {
|
|
1528
|
+
RelativeTargetResolver: () => RelativeTargetResolver
|
|
1529
|
+
});
|
|
1523
1530
|
var RelativeTargetResolver;
|
|
1524
1531
|
var init_RelativeTargetResolver = __esm({
|
|
1525
1532
|
"src/utils/test/src/RelativeTargetResolver.ts"() {
|
|
@@ -1595,16 +1602,16 @@ var init_ActionExecutor = __esm({
|
|
|
1595
1602
|
async focus(target, relativeTarget, virtualId) {
|
|
1596
1603
|
try {
|
|
1597
1604
|
if (target === "virtual" && virtualId) {
|
|
1598
|
-
const
|
|
1599
|
-
if (!
|
|
1600
|
-
return { success: false, error: `
|
|
1605
|
+
const mainSelector = this.selectors.main;
|
|
1606
|
+
if (!mainSelector) {
|
|
1607
|
+
return { success: false, error: `Main selector not defined for virtual focus.` };
|
|
1601
1608
|
}
|
|
1602
|
-
const
|
|
1603
|
-
const exists = await
|
|
1609
|
+
const main = this.page.locator(mainSelector).first();
|
|
1610
|
+
const exists = await main.count();
|
|
1604
1611
|
if (!exists) {
|
|
1605
|
-
return { success: false, error: `
|
|
1612
|
+
return { success: false, error: `Main element not found for virtual focus.` };
|
|
1606
1613
|
}
|
|
1607
|
-
await
|
|
1614
|
+
await main.evaluate((el, id) => {
|
|
1608
1615
|
el.setAttribute("aria-activedescendant", id);
|
|
1609
1616
|
}, virtualId);
|
|
1610
1617
|
return { success: true };
|
|
@@ -1906,6 +1913,10 @@ var init_AssertionRunner = __esm({
|
|
|
1906
1913
|
};
|
|
1907
1914
|
}
|
|
1908
1915
|
}
|
|
1916
|
+
if (typeof expectedValue !== "string") {
|
|
1917
|
+
console.error("[AssertionRunner] expectedValue is not a string:", expectedValue);
|
|
1918
|
+
throw new Error(`AssertionRunner: expectedValue for attribute assertion must be a string, but got: ${JSON.stringify(expectedValue)}`);
|
|
1919
|
+
}
|
|
1909
1920
|
const expectedValues = expectedValue.split(" | ").map((v) => v.trim());
|
|
1910
1921
|
const attributeValue = await target.getAttribute(attribute);
|
|
1911
1922
|
if (attributeValue !== null && expectedValues.includes(attributeValue)) {
|
|
@@ -1966,13 +1977,21 @@ var init_AssertionRunner = __esm({
|
|
|
1966
1977
|
/**
|
|
1967
1978
|
* Validate focus assertion
|
|
1968
1979
|
*/
|
|
1969
|
-
async validateFocus(target, targetName, failureMessage, testDescription) {
|
|
1980
|
+
async validateFocus(target, targetName, expectedFocus, failureMessage, testDescription) {
|
|
1970
1981
|
try {
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1982
|
+
if (expectedFocus) {
|
|
1983
|
+
await (0, test_exports.expect)(target).toBeFocused({ timeout: this.timeoutMs });
|
|
1984
|
+
return {
|
|
1985
|
+
success: true,
|
|
1986
|
+
passMessage: `${targetName} has focus as expected. Test: "${testDescription}".`
|
|
1987
|
+
};
|
|
1988
|
+
} else {
|
|
1989
|
+
await (0, test_exports.expect)(target).not.toBeFocused({ timeout: this.timeoutMs });
|
|
1990
|
+
return {
|
|
1991
|
+
success: true,
|
|
1992
|
+
passMessage: `${targetName} does not have focus as expected. Test: "${testDescription}".`
|
|
1993
|
+
};
|
|
1994
|
+
}
|
|
1976
1995
|
} catch {
|
|
1977
1996
|
const actualFocus = await this.page.evaluate(() => {
|
|
1978
1997
|
const focused = document.activeElement;
|
|
@@ -2058,7 +2077,9 @@ var init_AssertionRunner = __esm({
|
|
|
2058
2077
|
}
|
|
2059
2078
|
return { success: false, failMessage: "Missing expectedValue for toHaveValue assertion" };
|
|
2060
2079
|
case "toHaveFocus":
|
|
2061
|
-
return this.validateFocus(target, assertion.target, assertion.failureMessage || "", testDescription);
|
|
2080
|
+
return this.validateFocus(target, assertion.target, true, assertion.failureMessage || "", testDescription);
|
|
2081
|
+
case "notToHaveFocus":
|
|
2082
|
+
return this.validateFocus(target, assertion.target, false, assertion.failureMessage || "", testDescription);
|
|
2062
2083
|
case "toHaveRole":
|
|
2063
2084
|
if (assertion.expectedValue !== void 0) {
|
|
2064
2085
|
return this.validateRole(target, assertion.target, assertion.expectedValue, assertion.failureMessage || "", testDescription);
|
|
@@ -2338,6 +2359,52 @@ This usually means:
|
|
|
2338
2359
|
reporter.reportStaticTest(relDescription, "pass", void 0, relationshipLevel);
|
|
2339
2360
|
}
|
|
2340
2361
|
}
|
|
2362
|
+
async function resolveExpectedValue(expectedValue, selectors, page2, context = {}) {
|
|
2363
|
+
if (!expectedValue || typeof expectedValue !== "object" || !("ref" in expectedValue)) return expectedValue;
|
|
2364
|
+
let refSelector;
|
|
2365
|
+
if (expectedValue.ref === "relative") {
|
|
2366
|
+
if (!expectedValue.relativeTarget || !context.relativeBaseSelector) return void 0;
|
|
2367
|
+
const baseLocator = page2.locator(context.relativeBaseSelector);
|
|
2368
|
+
const count = await baseLocator.count();
|
|
2369
|
+
let idx = 0;
|
|
2370
|
+
if (expectedValue.relativeTarget === "first") idx = 0;
|
|
2371
|
+
else if (expectedValue.relativeTarget === "second") idx = 1;
|
|
2372
|
+
else if (expectedValue.relativeTarget === "last") idx = count - 1;
|
|
2373
|
+
else if (!isNaN(Number(expectedValue.relativeTarget))) idx = Number(expectedValue.relativeTarget);
|
|
2374
|
+
else idx = 0;
|
|
2375
|
+
if (idx < 0 || idx >= count) return void 0;
|
|
2376
|
+
const relElem = baseLocator.nth(idx);
|
|
2377
|
+
return await getPropertyFromLocator(relElem, expectedValue.property || expectedValue.attribute);
|
|
2378
|
+
} else {
|
|
2379
|
+
refSelector = selectors[expectedValue.ref];
|
|
2380
|
+
if (!refSelector) throw new Error(`Selector for ref '${expectedValue.ref}' not found in contract selectors.`);
|
|
2381
|
+
const refLocator = page2.locator(refSelector).first();
|
|
2382
|
+
return await getPropertyFromLocator(refLocator, expectedValue.property || expectedValue.attribute);
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
async function getPropertyFromLocator(locator, property) {
|
|
2386
|
+
if (!locator) return void 0;
|
|
2387
|
+
if (!property || property === "id") {
|
|
2388
|
+
return await locator.getAttribute("id") ?? void 0;
|
|
2389
|
+
} else if (property === "class") {
|
|
2390
|
+
return await locator.getAttribute("class") ?? void 0;
|
|
2391
|
+
} else if (property === "textContent") {
|
|
2392
|
+
return await locator.evaluate((el) => el.textContent ?? void 0);
|
|
2393
|
+
} else if (property.startsWith("aria-")) {
|
|
2394
|
+
return await locator.getAttribute(property) ?? void 0;
|
|
2395
|
+
} else if (property.endsWith("*")) {
|
|
2396
|
+
const attrs = await locator.evaluate((el) => {
|
|
2397
|
+
const out = [];
|
|
2398
|
+
for (const attr of Array.from(el.attributes)) {
|
|
2399
|
+
if (attr.name.startsWith("aria-")) out.push(`${attr.name}=${attr.value}`);
|
|
2400
|
+
}
|
|
2401
|
+
return out.join(";");
|
|
2402
|
+
});
|
|
2403
|
+
return attrs;
|
|
2404
|
+
} else {
|
|
2405
|
+
return await locator.getAttribute(property) ?? void 0;
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2341
2408
|
const staticAssertionRunner = new AssertionRunner(page, componentContract.selectors, assertionTimeoutMs);
|
|
2342
2409
|
for (const test of componentContract.static[0]?.assertions || []) {
|
|
2343
2410
|
if (test.target === "relative") continue;
|
|
@@ -2380,6 +2447,22 @@ This usually means:
|
|
|
2380
2447
|
}
|
|
2381
2448
|
return false;
|
|
2382
2449
|
};
|
|
2450
|
+
let expectedValue = test.expectedValue;
|
|
2451
|
+
if (test.expectedValue && typeof test.expectedValue === "object" && "ref" in test.expectedValue) {
|
|
2452
|
+
const context = {};
|
|
2453
|
+
const relTarget = test.relativeTarget;
|
|
2454
|
+
if (test.expectedValue.ref === "relative" && test.target === "relative" && relTarget) {
|
|
2455
|
+
const baseSel = componentContract.selectors[relTarget];
|
|
2456
|
+
if (!baseSel) throw new Error(`Selector for relativeTarget '${relTarget}' not found in contract selectors.`);
|
|
2457
|
+
context.relativeBaseSelector = baseSel;
|
|
2458
|
+
} else if (test.expectedValue.ref === "relative" && relTarget) {
|
|
2459
|
+
const baseSel = componentContract.selectors[relTarget];
|
|
2460
|
+
if (!baseSel) throw new Error(`Selector for relativeTarget '${relTarget}' not found in contract selectors.`);
|
|
2461
|
+
context.relativeBaseSelector = baseSel;
|
|
2462
|
+
}
|
|
2463
|
+
expectedValue = await resolveExpectedValue(test.expectedValue, componentContract.selectors, page, context);
|
|
2464
|
+
console.log("Expected value in static check", expectedValue);
|
|
2465
|
+
}
|
|
2383
2466
|
if (!test.expectedValue) {
|
|
2384
2467
|
const attributes = test.attribute.split(" | ");
|
|
2385
2468
|
let hasAny = false;
|
|
@@ -2413,16 +2496,17 @@ This usually means:
|
|
|
2413
2496
|
reporter.reportStaticTest(staticDescription, "pass", void 0, staticLevel);
|
|
2414
2497
|
}
|
|
2415
2498
|
} else {
|
|
2416
|
-
if (isRedundantCheck(targetSelector, test.attribute,
|
|
2417
|
-
passes.push(`${test.attribute}="${
|
|
2499
|
+
if (isRedundantCheck(targetSelector, test.attribute, typeof expectedValue === "string" ? expectedValue : void 0)) {
|
|
2500
|
+
passes.push(`${test.attribute}="${expectedValue}" on ${test.target} verified by selector (already present in: ${targetSelector}).`);
|
|
2418
2501
|
staticPassed += 1;
|
|
2419
2502
|
reporter.reportStaticTest(staticDescription, "pass", void 0, staticLevel);
|
|
2420
2503
|
} else {
|
|
2504
|
+
const valueToCheck = expectedValue ?? "";
|
|
2421
2505
|
const result = await staticAssertionRunner.validateAttribute(
|
|
2422
2506
|
target,
|
|
2423
2507
|
test.target,
|
|
2424
2508
|
test.attribute,
|
|
2425
|
-
|
|
2509
|
+
valueToCheck,
|
|
2426
2510
|
test.failureMessage,
|
|
2427
2511
|
"Static ARIA Test"
|
|
2428
2512
|
);
|
|
@@ -2540,7 +2624,33 @@ This usually means:
|
|
|
2540
2624
|
continue;
|
|
2541
2625
|
}
|
|
2542
2626
|
for (const assertion of assertions) {
|
|
2543
|
-
|
|
2627
|
+
let expectedValue;
|
|
2628
|
+
if (assertion.expectedValue && typeof assertion.expectedValue === "object" && "ref" in assertion.expectedValue) {
|
|
2629
|
+
if (assertion.expectedValue.ref === "relative") {
|
|
2630
|
+
const { RelativeTargetResolver: RelativeTargetResolver2 } = await Promise.resolve().then(() => (init_RelativeTargetResolver(), RelativeTargetResolver_exports));
|
|
2631
|
+
const relativeSelector = componentContract.selectors.relative;
|
|
2632
|
+
if (!relativeSelector) throw new Error("Relative selector not defined in contract selectors.");
|
|
2633
|
+
const relTarget = assertion.relativeTarget || "first";
|
|
2634
|
+
const relElem = await RelativeTargetResolver2.resolve(page, relativeSelector, relTarget);
|
|
2635
|
+
if (!relElem) throw new Error(`Could not resolve relative target '${relTarget}' for expectedValue.`);
|
|
2636
|
+
const prop = assertion.expectedValue.property || assertion.expectedValue.attribute || "id";
|
|
2637
|
+
if (prop === "textContent") {
|
|
2638
|
+
expectedValue = await relElem.evaluate((el) => el.textContent ?? void 0);
|
|
2639
|
+
} else {
|
|
2640
|
+
const attr = await relElem.getAttribute(prop);
|
|
2641
|
+
expectedValue = attr === null ? void 0 : attr;
|
|
2642
|
+
}
|
|
2643
|
+
} else {
|
|
2644
|
+
expectedValue = await resolveExpectedValue(assertion.expectedValue, componentContract.selectors, page, {});
|
|
2645
|
+
}
|
|
2646
|
+
} else if (typeof assertion.expectedValue === "string" || typeof assertion.expectedValue === "undefined") {
|
|
2647
|
+
expectedValue = assertion.expectedValue;
|
|
2648
|
+
} else {
|
|
2649
|
+
expectedValue = "";
|
|
2650
|
+
}
|
|
2651
|
+
const assertionToRun = { ...assertion, expectedValue };
|
|
2652
|
+
const valueToCheck = expectedValue ?? "";
|
|
2653
|
+
const result = await assertionRunner.validate({ ...assertionToRun, expectedValue: valueToCheck }, dynamicTest.description);
|
|
2544
2654
|
if (result.success && result.passMessage) {
|
|
2545
2655
|
passes.push(result.passMessage);
|
|
2546
2656
|
} else if (!result.success && result.failMessage) {
|
package/dist/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ var program = new Command();
|
|
|
17
17
|
program.name("aria-ease").description("Run accessibility tests and audits").version("2.2.3");
|
|
18
18
|
program.command("audit").description("Run axe-core powered accessibility audit on webpages").option("-u, --url <url>", "Single URL to audit").option("-f, --format <format>", "Output format for the audit report: json | csv | html | all", "all").option("-o, --out <path>", "Directory to save the audit report", "./accessibility-reports/audit").action(async (opts) => {
|
|
19
19
|
console.log(chalk.cyanBright("\u{1F680} Starting accessibility audit...\n"));
|
|
20
|
-
const { runAudit } = await import("./audit-
|
|
20
|
+
const { runAudit } = await import("./audit-JYEPKLHR.js");
|
|
21
21
|
const { formatResults } = await import("./formatters-32KQIIYS.js");
|
|
22
22
|
const needsConfig = !opts.url;
|
|
23
23
|
const { config, configPath, errors } = await loadConfig(process.cwd());
|
|
@@ -50,7 +50,7 @@ program.command("audit").description("Run axe-core powered accessibility audit o
|
|
|
50
50
|
process.exit(1);
|
|
51
51
|
}
|
|
52
52
|
const allResults = [];
|
|
53
|
-
const { createAuditBrowser } = await import("./audit-
|
|
53
|
+
const { createAuditBrowser } = await import("./audit-JYEPKLHR.js");
|
|
54
54
|
const browser = await createAuditBrowser();
|
|
55
55
|
try {
|
|
56
56
|
const auditOptions = { browser };
|
|
@@ -122,7 +122,7 @@ program.command("audit").description("Run axe-core powered accessibility audit o
|
|
|
122
122
|
process.exit(1);
|
|
123
123
|
});
|
|
124
124
|
program.command("test").description("Run core a11y accessibility standard tests on UI components").action(async () => {
|
|
125
|
-
const { runTest } = await import("./test-
|
|
125
|
+
const { runTest } = await import("./test-6Y4CIQOM.js");
|
|
126
126
|
runTest();
|
|
127
127
|
});
|
|
128
128
|
program.command("build").description("Build accessibility artifacts").addCommand(
|