aria-ease 2.8.4 → 2.9.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.
- package/bin/{audit-XABLAI36.js → audit-XZJXMUPL.js} +2 -3
- package/bin/{chunk-JGKPHTSR.js → chunk-5Z7PR3VC.js} +4 -0
- package/bin/cli.cjs +197 -50
- package/bin/cli.js +4 -4
- package/bin/{contractTestRunnerPlaywright-VDTXMVK5.js → contractTestRunnerPlaywright-62LXHK7K.js} +111 -12
- package/bin/{formatters-2RPHPXW2.js → formatters-U4E5EVPL.js} +23 -16
- package/bin/{test-N6M7MDBZ.js → test-PK5MBHIN.js} +55 -17
- package/dist/{chunk-SSBW5VAA.js → chunk-57O4KFP4.js} +4 -0
- package/dist/{contractTestRunnerPlaywright-AJ2DOOJT.js → contractTestRunnerPlaywright-LGXSV2ZS.js} +111 -12
- package/dist/index.cjs +409 -26
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +296 -17
- package/dist/src/Types.d-uG0Hm1yK.d.cts +39 -0
- package/dist/src/Types.d-uG0Hm1yK.d.ts +39 -0
- package/dist/src/accordion/index.d.cts +1 -1
- package/dist/src/accordion/index.d.ts +1 -1
- package/dist/src/block/index.d.cts +1 -1
- package/dist/src/block/index.d.ts +1 -1
- package/dist/src/checkbox/index.d.cts +1 -1
- package/dist/src/checkbox/index.d.ts +1 -1
- package/dist/src/combobox/index.cjs +243 -0
- package/dist/src/combobox/index.d.cts +14 -0
- package/dist/src/combobox/index.d.ts +14 -0
- package/dist/src/combobox/index.js +241 -0
- package/dist/src/menu/index.d.cts +1 -1
- package/dist/src/menu/index.d.ts +1 -1
- package/dist/src/radio/index.d.cts +1 -1
- package/dist/src/radio/index.d.ts +1 -1
- package/dist/src/toggle/index.d.cts +1 -1
- package/dist/src/toggle/index.d.ts +1 -1
- package/dist/src/utils/test/{chunk-SSBW5VAA.js → chunk-57O4KFP4.js} +4 -0
- package/dist/src/utils/test/{contractTestRunnerPlaywright-AJ2DOOJT.js → contractTestRunnerPlaywright-LGXSV2ZS.js} +111 -12
- package/dist/src/utils/test/contracts/ComboboxContract.json +474 -0
- package/dist/src/utils/test/index.cjs +167 -26
- package/dist/src/utils/test/index.js +55 -17
- package/package.json +9 -3
- package/bin/contractTestRunnerPlaywright-EHQAMXQA.js +0 -258
- package/bin/test-S2U633GD.js +0 -12804
- package/dist/contractTestRunnerPlaywright-7O2T4JES.js +0 -257
- package/dist/src/Types.d-w1KLKLcA.d.cts +0 -24
- package/dist/src/Types.d-w1KLKLcA.d.ts +0 -24
- package/dist/src/utils/test/contractTestRunnerPlaywright-7O2T4JES.js +0 -252
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./chunk-JSBRDJBE.js";
|
|
2
2
|
|
|
3
|
-
// src/utils/audit/src/audit/audit.
|
|
3
|
+
// src/utils/audit/src/audit/audit.ts
|
|
4
4
|
import AxeBuilder from "@axe-core/playwright";
|
|
5
5
|
import { chromium } from "playwright";
|
|
6
6
|
async function runAudit(url, options) {
|
|
@@ -38,8 +38,7 @@ async function runAudit(url, options) {
|
|
|
38
38
|
}
|
|
39
39
|
throw error;
|
|
40
40
|
} finally {
|
|
41
|
-
if (browser)
|
|
42
|
-
await browser.close();
|
|
41
|
+
if (browser) await browser.close();
|
|
43
42
|
}
|
|
44
43
|
}
|
|
45
44
|
export {
|
package/bin/cli.cjs
CHANGED
|
@@ -33,7 +33,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
33
33
|
mod
|
|
34
34
|
));
|
|
35
35
|
|
|
36
|
-
// src/utils/audit/src/audit/audit.
|
|
36
|
+
// src/utils/audit/src/audit/audit.ts
|
|
37
37
|
var audit_exports = {};
|
|
38
38
|
__export(audit_exports, {
|
|
39
39
|
runAudit: () => runAudit
|
|
@@ -73,20 +73,19 @@ async function runAudit(url, options) {
|
|
|
73
73
|
}
|
|
74
74
|
throw error;
|
|
75
75
|
} finally {
|
|
76
|
-
if (browser)
|
|
77
|
-
await browser.close();
|
|
76
|
+
if (browser) await browser.close();
|
|
78
77
|
}
|
|
79
78
|
}
|
|
80
79
|
var import_playwright, import_playwright2;
|
|
81
80
|
var init_audit = __esm({
|
|
82
|
-
"src/utils/audit/src/audit/audit.
|
|
81
|
+
"src/utils/audit/src/audit/audit.ts"() {
|
|
83
82
|
"use strict";
|
|
84
83
|
import_playwright = __toESM(require("@axe-core/playwright"), 1);
|
|
85
84
|
import_playwright2 = require("playwright");
|
|
86
85
|
}
|
|
87
86
|
});
|
|
88
87
|
|
|
89
|
-
// src/utils/audit/src/formatters/formatters.
|
|
88
|
+
// src/utils/audit/src/formatters/formatters.ts
|
|
90
89
|
var formatters_exports = {};
|
|
91
90
|
__export(formatters_exports, {
|
|
92
91
|
formatResults: () => formatResults
|
|
@@ -94,14 +93,22 @@ __export(formatters_exports, {
|
|
|
94
93
|
function formatResults(allResults, format2) {
|
|
95
94
|
switch (format2) {
|
|
96
95
|
case "json":
|
|
97
|
-
return JSON.stringify(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
96
|
+
return JSON.stringify(
|
|
97
|
+
allResults.flatMap(
|
|
98
|
+
({ url, result }) => result ? result.violations.flatMap(
|
|
99
|
+
(v) => v.nodes.map((n) => ({
|
|
100
|
+
URL: url,
|
|
101
|
+
Rule: v.id,
|
|
102
|
+
Impact: v.impact,
|
|
103
|
+
Description: v.description,
|
|
104
|
+
Target: n.target,
|
|
105
|
+
FailureSummary: n.failureSummary
|
|
106
|
+
}))
|
|
107
|
+
) : []
|
|
108
|
+
),
|
|
109
|
+
null,
|
|
110
|
+
2
|
|
111
|
+
);
|
|
105
112
|
case "csv":
|
|
106
113
|
return toCSV(allResults);
|
|
107
114
|
case "html":
|
|
@@ -116,7 +123,9 @@ function toCSV(allResults) {
|
|
|
116
123
|
if (result) {
|
|
117
124
|
result.violations.forEach((v) => {
|
|
118
125
|
v.nodes.forEach((n) => {
|
|
119
|
-
rows.push(
|
|
126
|
+
rows.push(
|
|
127
|
+
escapeCSV(url) + "," + escapeCSV(v.id) + "," + escapeCSV(v.impact) + "," + escapeCSV(v.description) + "," + escapeCSV(Array.isArray(n.target) ? n.target.join("; ") : String(n.target)) + "," + escapeCSV(n.failureSummary ?? "")
|
|
128
|
+
);
|
|
120
129
|
});
|
|
121
130
|
});
|
|
122
131
|
}
|
|
@@ -136,8 +145,7 @@ function toHTML(allResults) {
|
|
|
136
145
|
impactCounts: /* @__PURE__ */ new Map()
|
|
137
146
|
};
|
|
138
147
|
allResults.forEach(({ result }) => {
|
|
139
|
-
if (!result)
|
|
140
|
-
return;
|
|
148
|
+
if (!result) return;
|
|
141
149
|
summary.pagesAudited++;
|
|
142
150
|
const pageViolations = result.violations.reduce((acc, v) => {
|
|
143
151
|
const nodesCount = (v.nodes || []).length;
|
|
@@ -150,13 +158,11 @@ function toHTML(allResults) {
|
|
|
150
158
|
}
|
|
151
159
|
return acc;
|
|
152
160
|
}, 0);
|
|
153
|
-
if (pageViolations > 0)
|
|
154
|
-
summary.pagesWithViolations++;
|
|
161
|
+
if (pageViolations > 0) summary.pagesWithViolations++;
|
|
155
162
|
});
|
|
156
163
|
const rows = [];
|
|
157
164
|
allResults.forEach(({ url, result }) => {
|
|
158
|
-
if (!result)
|
|
159
|
-
return;
|
|
165
|
+
if (!result) return;
|
|
160
166
|
result.violations.forEach((v) => {
|
|
161
167
|
v.nodes.forEach((n) => {
|
|
162
168
|
const target = Array.isArray(n.target) ? n.target.join("; ") : String(n.target);
|
|
@@ -262,7 +268,7 @@ function escapeClass(s) {
|
|
|
262
268
|
return String(s ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
263
269
|
}
|
|
264
270
|
var init_formatters = __esm({
|
|
265
|
-
"src/utils/audit/src/formatters/formatters.
|
|
271
|
+
"src/utils/audit/src/formatters/formatters.ts"() {
|
|
266
272
|
"use strict";
|
|
267
273
|
}
|
|
268
274
|
});
|
|
@@ -275,6 +281,10 @@ var init_contract = __esm({
|
|
|
275
281
|
menu: {
|
|
276
282
|
path: "./contracts/MenuContract.json",
|
|
277
283
|
component: "menu"
|
|
284
|
+
},
|
|
285
|
+
combobox: {
|
|
286
|
+
path: "./contracts/ComboboxContract.json",
|
|
287
|
+
component: "combobox"
|
|
278
288
|
}
|
|
279
289
|
};
|
|
280
290
|
}
|
|
@@ -13018,7 +13028,12 @@ async function runContractTests(componentName, component) {
|
|
|
13018
13028
|
const skipped = [];
|
|
13019
13029
|
for (const test of componentContract.static[0].assertions) {
|
|
13020
13030
|
if (test.target !== "relative") {
|
|
13021
|
-
const
|
|
13031
|
+
const selector = componentContract.selectors[test.target];
|
|
13032
|
+
if (!selector) {
|
|
13033
|
+
failures.push(`Selector for target ${test.target} not found.`);
|
|
13034
|
+
continue;
|
|
13035
|
+
}
|
|
13036
|
+
const target = component.querySelector(selector);
|
|
13022
13037
|
if (!target) {
|
|
13023
13038
|
failures.push(`Target ${test.target} not found.`);
|
|
13024
13039
|
continue;
|
|
@@ -13076,13 +13091,17 @@ async function runContractTests(componentName, component) {
|
|
|
13076
13091
|
}
|
|
13077
13092
|
const { action, assertions } = dynamicTest;
|
|
13078
13093
|
const failuresBeforeTest = failures.length;
|
|
13079
|
-
const
|
|
13080
|
-
const
|
|
13081
|
-
if (
|
|
13082
|
-
const
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13094
|
+
const containerSelector = componentContract.selectors.container;
|
|
13095
|
+
const triggerSelector = componentContract.selectors.trigger;
|
|
13096
|
+
if (containerSelector && triggerSelector) {
|
|
13097
|
+
const containerElement = component.querySelector(containerSelector);
|
|
13098
|
+
const triggerElement = component.querySelector(triggerSelector);
|
|
13099
|
+
if (containerElement && triggerElement) {
|
|
13100
|
+
const isContainerVisible = containerElement.style.display !== "none";
|
|
13101
|
+
if (isContainerVisible) {
|
|
13102
|
+
fireEvent.click(triggerElement);
|
|
13103
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
13104
|
+
}
|
|
13086
13105
|
}
|
|
13087
13106
|
}
|
|
13088
13107
|
const preActionExpectedTargets = /* @__PURE__ */ new Map();
|
|
@@ -13099,7 +13118,12 @@ async function runContractTests(componentName, component) {
|
|
|
13099
13118
|
if (act.target === "document") {
|
|
13100
13119
|
fireEvent.click(document.body);
|
|
13101
13120
|
} else {
|
|
13102
|
-
const
|
|
13121
|
+
const selector = componentContract.selectors[act.target];
|
|
13122
|
+
if (!selector) {
|
|
13123
|
+
failures.push(`Selector for action target ${act.target} not found.`);
|
|
13124
|
+
continue;
|
|
13125
|
+
}
|
|
13126
|
+
const target = component.querySelector(selector);
|
|
13103
13127
|
if (target instanceof HTMLElement) {
|
|
13104
13128
|
target.focus();
|
|
13105
13129
|
fireEvent.click(target);
|
|
@@ -13113,16 +13137,27 @@ async function runContractTests(componentName, component) {
|
|
|
13113
13137
|
let target;
|
|
13114
13138
|
if (act.target === "focusable" && ["Arrow Up", "Arrow Down", "Arrow Left", "Arrow Right", "Escape"].includes(act.key || "")) {
|
|
13115
13139
|
const activeElement = document.activeElement;
|
|
13116
|
-
const
|
|
13117
|
-
const
|
|
13140
|
+
const containerSelector2 = componentContract.selectors.container;
|
|
13141
|
+
const focusableSelector = componentContract.selectors.focusable;
|
|
13142
|
+
if (!containerSelector2 || !focusableSelector) {
|
|
13143
|
+
failures.push(`Container or focusable selector not found.`);
|
|
13144
|
+
continue;
|
|
13145
|
+
}
|
|
13146
|
+
const containerElement = component.querySelector(containerSelector2);
|
|
13147
|
+
const focusableItems = containerElement?.querySelectorAll(focusableSelector);
|
|
13118
13148
|
if (focusableItems && focusableItems.length > 0) {
|
|
13119
13149
|
const focusedItem = Array.from(focusableItems).find((item) => item === activeElement);
|
|
13120
13150
|
target = focusedItem || focusableItems[0];
|
|
13121
13151
|
} else {
|
|
13122
|
-
target =
|
|
13152
|
+
target = containerElement;
|
|
13123
13153
|
}
|
|
13124
13154
|
} else {
|
|
13125
|
-
|
|
13155
|
+
const selector = componentContract.selectors[act.target];
|
|
13156
|
+
if (!selector) {
|
|
13157
|
+
failures.push(`Selector for keypress target ${act.target} not found.`);
|
|
13158
|
+
continue;
|
|
13159
|
+
}
|
|
13160
|
+
target = component.querySelector(selector);
|
|
13126
13161
|
}
|
|
13127
13162
|
if (target) {
|
|
13128
13163
|
target.focus();
|
|
@@ -13164,7 +13199,12 @@ async function runContractTests(componentName, component) {
|
|
|
13164
13199
|
}
|
|
13165
13200
|
target = resolveRelativeTarget(component, relativeSelector, assertion.expectedValue);
|
|
13166
13201
|
} else {
|
|
13167
|
-
|
|
13202
|
+
const selector = componentContract.selectors[assertion.target];
|
|
13203
|
+
if (!selector) {
|
|
13204
|
+
failures.push(`Selector for assertion target ${assertion.target} not found.`);
|
|
13205
|
+
continue;
|
|
13206
|
+
}
|
|
13207
|
+
target = component.querySelector(selector);
|
|
13168
13208
|
}
|
|
13169
13209
|
if (!target) {
|
|
13170
13210
|
failures.push(`Target ${assertion.target} not found.`);
|
|
@@ -13262,7 +13302,11 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
13262
13302
|
waitUntil: "domcontentloaded",
|
|
13263
13303
|
timeout: 6e4
|
|
13264
13304
|
});
|
|
13265
|
-
|
|
13305
|
+
const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
|
|
13306
|
+
if (!mainSelector) {
|
|
13307
|
+
throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
|
|
13308
|
+
}
|
|
13309
|
+
await page.waitForSelector(mainSelector, { timeout: 6e4 });
|
|
13266
13310
|
async function resolveRelativeTarget(selector, relative) {
|
|
13267
13311
|
const items = await page.locator(selector).all();
|
|
13268
13312
|
switch (relative) {
|
|
@@ -13333,17 +13377,61 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
13333
13377
|
for (const dynamicTest of componentContract.dynamic || []) {
|
|
13334
13378
|
const { action, assertions } = dynamicTest;
|
|
13335
13379
|
const failuresBeforeTest = failures.length;
|
|
13336
|
-
|
|
13337
|
-
|
|
13338
|
-
|
|
13339
|
-
|
|
13340
|
-
await
|
|
13341
|
-
|
|
13380
|
+
if (componentContract.selectors.listbox || componentContract.selectors.container) {
|
|
13381
|
+
const popupSelector = componentContract.selectors.listbox || componentContract.selectors.container;
|
|
13382
|
+
if (!popupSelector) continue;
|
|
13383
|
+
const popupElement = page.locator(popupSelector).first();
|
|
13384
|
+
const isPopupVisible = await popupElement.isVisible();
|
|
13385
|
+
if (isPopupVisible) {
|
|
13386
|
+
const closeSelector = componentContract.selectors.input || componentContract.selectors.trigger;
|
|
13387
|
+
if (closeSelector) {
|
|
13388
|
+
const closeElement = page.locator(closeSelector).first();
|
|
13389
|
+
await closeElement.focus();
|
|
13390
|
+
await page.keyboard.press("Escape");
|
|
13391
|
+
await page.waitForTimeout(200);
|
|
13392
|
+
if (componentContract.selectors.input) {
|
|
13393
|
+
const inputElement = page.locator(componentContract.selectors.input).first();
|
|
13394
|
+
await inputElement.clear();
|
|
13395
|
+
await page.waitForTimeout(50);
|
|
13396
|
+
}
|
|
13397
|
+
}
|
|
13398
|
+
}
|
|
13342
13399
|
}
|
|
13343
13400
|
for (const act of action) {
|
|
13401
|
+
if (act.type === "focus") {
|
|
13402
|
+
const focusSelector = componentContract.selectors[act.target];
|
|
13403
|
+
if (!focusSelector) {
|
|
13404
|
+
failures.push(`Selector for focus target ${act.target} not found.`);
|
|
13405
|
+
continue;
|
|
13406
|
+
}
|
|
13407
|
+
await page.locator(focusSelector).first().focus();
|
|
13408
|
+
await page.waitForTimeout(50);
|
|
13409
|
+
}
|
|
13410
|
+
if (act.type === "type" && act.value) {
|
|
13411
|
+
const typeSelector = componentContract.selectors[act.target];
|
|
13412
|
+
if (!typeSelector) {
|
|
13413
|
+
failures.push(`Selector for type target ${act.target} not found.`);
|
|
13414
|
+
continue;
|
|
13415
|
+
}
|
|
13416
|
+
await page.locator(typeSelector).first().fill(act.value);
|
|
13417
|
+
await page.waitForTimeout(50);
|
|
13418
|
+
}
|
|
13344
13419
|
if (act.type === "click") {
|
|
13345
13420
|
if (act.target === "document") {
|
|
13346
13421
|
await page.mouse.click(10, 10);
|
|
13422
|
+
} else if (act.target === "relative" && act.relativeTarget) {
|
|
13423
|
+
const relativeSelector = componentContract.selectors.relative;
|
|
13424
|
+
if (!relativeSelector) {
|
|
13425
|
+
failures.push(`Relative selector not defined for click action.`);
|
|
13426
|
+
continue;
|
|
13427
|
+
}
|
|
13428
|
+
const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
|
|
13429
|
+
if (!relativeElement) {
|
|
13430
|
+
failures.push(`Could not resolve relative target ${act.relativeTarget} for click.`);
|
|
13431
|
+
continue;
|
|
13432
|
+
}
|
|
13433
|
+
await relativeElement.click();
|
|
13434
|
+
await page.waitForTimeout(200);
|
|
13347
13435
|
} else {
|
|
13348
13436
|
const actionSelector = componentContract.selectors[act.target];
|
|
13349
13437
|
if (!actionSelector) {
|
|
@@ -13392,6 +13480,30 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
13392
13480
|
await target.press(keyValue);
|
|
13393
13481
|
}
|
|
13394
13482
|
}
|
|
13483
|
+
if (act.type === "hover") {
|
|
13484
|
+
if (act.target === "relative" && act.relativeTarget) {
|
|
13485
|
+
const relativeSelector = componentContract.selectors.relative;
|
|
13486
|
+
if (!relativeSelector) {
|
|
13487
|
+
failures.push(`Relative selector not defined for hover action.`);
|
|
13488
|
+
continue;
|
|
13489
|
+
}
|
|
13490
|
+
const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
|
|
13491
|
+
if (!relativeElement) {
|
|
13492
|
+
failures.push(`Could not resolve relative target ${act.relativeTarget} for hover.`);
|
|
13493
|
+
continue;
|
|
13494
|
+
}
|
|
13495
|
+
await relativeElement.hover();
|
|
13496
|
+
await page.waitForTimeout(50);
|
|
13497
|
+
} else {
|
|
13498
|
+
const hoverSelector = componentContract.selectors[act.target];
|
|
13499
|
+
if (!hoverSelector) {
|
|
13500
|
+
failures.push(`Selector for hover target ${act.target} not found.`);
|
|
13501
|
+
continue;
|
|
13502
|
+
}
|
|
13503
|
+
await page.locator(hoverSelector).first().hover();
|
|
13504
|
+
await page.waitForTimeout(50);
|
|
13505
|
+
}
|
|
13506
|
+
}
|
|
13395
13507
|
await page.waitForTimeout(100);
|
|
13396
13508
|
}
|
|
13397
13509
|
for (const assertion of assertions) {
|
|
@@ -13402,11 +13514,12 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
13402
13514
|
failures.push("Relative selector is not defined in the contract.");
|
|
13403
13515
|
continue;
|
|
13404
13516
|
}
|
|
13405
|
-
|
|
13406
|
-
|
|
13517
|
+
const relativeTargetValue = assertion.relativeTarget || assertion.expectedValue;
|
|
13518
|
+
if (!relativeTargetValue) {
|
|
13519
|
+
failures.push("Relative target or expected value is not defined.");
|
|
13407
13520
|
continue;
|
|
13408
13521
|
}
|
|
13409
|
-
target = await resolveRelativeTarget(relativeSelector,
|
|
13522
|
+
target = await resolveRelativeTarget(relativeSelector, relativeTargetValue);
|
|
13410
13523
|
} else {
|
|
13411
13524
|
const assertionSelector = componentContract.selectors[assertion.target];
|
|
13412
13525
|
if (!assertionSelector) {
|
|
@@ -13437,12 +13550,38 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
13437
13550
|
}
|
|
13438
13551
|
if (assertion.assertion === "toHaveAttribute" && assertion.attribute && assertion.expectedValue) {
|
|
13439
13552
|
const attributeValue = await target.getAttribute(assertion.attribute);
|
|
13440
|
-
if (
|
|
13553
|
+
if (assertion.expectedValue === "!empty") {
|
|
13554
|
+
if (attributeValue && attributeValue.trim() !== "") {
|
|
13555
|
+
passes.push(`${assertion.target} has non-empty "${assertion.attribute}". Test: "${dynamicTest.description}".`);
|
|
13556
|
+
} else {
|
|
13557
|
+
failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should not be empty, found "${attributeValue}".`);
|
|
13558
|
+
}
|
|
13559
|
+
} else if (attributeValue === assertion.expectedValue) {
|
|
13441
13560
|
passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
|
|
13442
13561
|
} else {
|
|
13443
13562
|
failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should be "${assertion.expectedValue}", found "${attributeValue}".`);
|
|
13444
13563
|
}
|
|
13445
13564
|
}
|
|
13565
|
+
if (assertion.assertion === "toHaveValue") {
|
|
13566
|
+
const inputValue = await target.inputValue().catch(() => "");
|
|
13567
|
+
if (assertion.expectedValue === "!empty") {
|
|
13568
|
+
if (inputValue && inputValue.trim() !== "") {
|
|
13569
|
+
passes.push(`${assertion.target} has non-empty value. Test: "${dynamicTest.description}".`);
|
|
13570
|
+
} else {
|
|
13571
|
+
failures.push(assertion.failureMessage + ` ${assertion.target} value should not be empty, found "${inputValue}".`);
|
|
13572
|
+
}
|
|
13573
|
+
} else if (assertion.expectedValue === "") {
|
|
13574
|
+
if (inputValue === "") {
|
|
13575
|
+
passes.push(`${assertion.target} has empty value. Test: "${dynamicTest.description}".`);
|
|
13576
|
+
} else {
|
|
13577
|
+
failures.push(assertion.failureMessage + ` ${assertion.target} value should be empty, found "${inputValue}".`);
|
|
13578
|
+
}
|
|
13579
|
+
} else if (inputValue === assertion.expectedValue) {
|
|
13580
|
+
passes.push(`${assertion.target} has expected value. Test: "${dynamicTest.description}".`);
|
|
13581
|
+
} else {
|
|
13582
|
+
failures.push(assertion.failureMessage + ` ${assertion.target} value should be "${assertion.expectedValue}", found "${inputValue}".`);
|
|
13583
|
+
}
|
|
13584
|
+
}
|
|
13446
13585
|
if (assertion.assertion === "toHaveFocus") {
|
|
13447
13586
|
const hasFocus = await target.evaluate((el) => el === document.activeElement);
|
|
13448
13587
|
if (hasFocus) {
|
|
@@ -13531,11 +13670,19 @@ async function testUiComponent(componentName, component, url) {
|
|
|
13531
13670
|
}
|
|
13532
13671
|
if (results.violations.length > 0) {
|
|
13533
13672
|
const violationCount = results.violations.length;
|
|
13673
|
+
const violationDetails = results.violations.map(
|
|
13674
|
+
(v) => `
|
|
13675
|
+
- ${v.id}: ${v.description}
|
|
13676
|
+
Impact: ${v.impact}
|
|
13677
|
+
Affected elements: ${v.nodes.length}
|
|
13678
|
+
Help: ${v.helpUrl}`
|
|
13679
|
+
).join("\n");
|
|
13534
13680
|
throw new Error(
|
|
13535
13681
|
`
|
|
13536
13682
|
\u274C ${violationCount} axe accessibility violation${violationCount > 1 ? "s" : ""} detected
|
|
13683
|
+
${violationDetails}
|
|
13537
13684
|
|
|
13538
|
-
\u{1F4CB}
|
|
13685
|
+
\u{1F4CB} Full details available in result.violations`
|
|
13539
13686
|
);
|
|
13540
13687
|
}
|
|
13541
13688
|
return result;
|
|
@@ -13573,14 +13720,14 @@ var init_test = __esm({
|
|
|
13573
13720
|
}
|
|
13574
13721
|
});
|
|
13575
13722
|
|
|
13576
|
-
// src/utils/test/index.
|
|
13723
|
+
// src/utils/test/index.ts
|
|
13577
13724
|
var test_exports = {};
|
|
13578
13725
|
__export(test_exports, {
|
|
13579
13726
|
runTest: () => runTest,
|
|
13580
13727
|
testUiComponent: () => testUiComponent
|
|
13581
13728
|
});
|
|
13582
13729
|
var init_test2 = __esm({
|
|
13583
|
-
"src/utils/test/index.
|
|
13730
|
+
"src/utils/test/index.ts"() {
|
|
13584
13731
|
"use strict";
|
|
13585
13732
|
init_test();
|
|
13586
13733
|
}
|
|
@@ -13592,7 +13739,7 @@ var import_chalk = __toESM(require("chalk"), 1);
|
|
|
13592
13739
|
var import_path2 = __toESM(require("path"), 1);
|
|
13593
13740
|
var import_fs_extra2 = __toESM(require("fs-extra"), 1);
|
|
13594
13741
|
|
|
13595
|
-
// src/utils/cli/configLoader.
|
|
13742
|
+
// src/utils/cli/configLoader.ts
|
|
13596
13743
|
var import_path = __toESM(require("path"), 1);
|
|
13597
13744
|
var import_fs_extra = __toESM(require("fs-extra"), 1);
|
|
13598
13745
|
function validateConfig(config2) {
|
package/bin/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import chalk from "chalk";
|
|
|
7
7
|
import path2 from "path";
|
|
8
8
|
import fs2 from "fs-extra";
|
|
9
9
|
|
|
10
|
-
// src/utils/cli/configLoader.
|
|
10
|
+
// src/utils/cli/configLoader.ts
|
|
11
11
|
import path from "path";
|
|
12
12
|
import fs from "fs-extra";
|
|
13
13
|
function validateConfig(config) {
|
|
@@ -128,8 +128,8 @@ var program = new Command();
|
|
|
128
128
|
program.name("aria-ease").description("Run accessibility tests and audits").version("2.2.3");
|
|
129
129
|
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) => {
|
|
130
130
|
console.log(chalk.cyanBright("\u{1F680} Starting accessibility audit...\n"));
|
|
131
|
-
const { runAudit } = await import("./audit-
|
|
132
|
-
const { formatResults } = await import("./formatters-
|
|
131
|
+
const { runAudit } = await import("./audit-XZJXMUPL.js");
|
|
132
|
+
const { formatResults } = await import("./formatters-U4E5EVPL.js");
|
|
133
133
|
const { config, configPath, errors } = await loadConfig(process.cwd());
|
|
134
134
|
if (configPath) {
|
|
135
135
|
console.log(chalk.green(`\u2705 Loaded config from ${path2.basename(configPath)}
|
|
@@ -204,7 +204,7 @@ program.command("audit").description("Run axe-core powered accessibility audit o
|
|
|
204
204
|
console.log(chalk.green("\n\u{1F389} All audits completed."));
|
|
205
205
|
});
|
|
206
206
|
program.command("test").description("Run core a11y accessibility standard tests on UI components").action(async () => {
|
|
207
|
-
const { runTest } = await import("./test-
|
|
207
|
+
const { runTest } = await import("./test-PK5MBHIN.js");
|
|
208
208
|
runTest();
|
|
209
209
|
});
|
|
210
210
|
program.command("help").description("Display help information").action(() => {
|
package/bin/{contractTestRunnerPlaywright-VDTXMVK5.js → contractTestRunnerPlaywright-62LXHK7K.js}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ContractReporter,
|
|
3
3
|
contract_default
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5Z7PR3VC.js";
|
|
5
5
|
import "./chunk-JSBRDJBE.js";
|
|
6
6
|
|
|
7
7
|
// src/utils/test/contract/contractTestRunnerPlaywright.ts
|
|
@@ -30,7 +30,11 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
30
30
|
waitUntil: "domcontentloaded",
|
|
31
31
|
timeout: 6e4
|
|
32
32
|
});
|
|
33
|
-
|
|
33
|
+
const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
|
|
34
|
+
if (!mainSelector) {
|
|
35
|
+
throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
|
|
36
|
+
}
|
|
37
|
+
await page.waitForSelector(mainSelector, { timeout: 6e4 });
|
|
34
38
|
async function resolveRelativeTarget(selector, relative) {
|
|
35
39
|
const items = await page.locator(selector).all();
|
|
36
40
|
switch (relative) {
|
|
@@ -101,17 +105,61 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
101
105
|
for (const dynamicTest of componentContract.dynamic || []) {
|
|
102
106
|
const { action, assertions } = dynamicTest;
|
|
103
107
|
const failuresBeforeTest = failures.length;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
await
|
|
109
|
-
|
|
108
|
+
if (componentContract.selectors.listbox || componentContract.selectors.container) {
|
|
109
|
+
const popupSelector = componentContract.selectors.listbox || componentContract.selectors.container;
|
|
110
|
+
if (!popupSelector) continue;
|
|
111
|
+
const popupElement = page.locator(popupSelector).first();
|
|
112
|
+
const isPopupVisible = await popupElement.isVisible();
|
|
113
|
+
if (isPopupVisible) {
|
|
114
|
+
const closeSelector = componentContract.selectors.input || componentContract.selectors.trigger;
|
|
115
|
+
if (closeSelector) {
|
|
116
|
+
const closeElement = page.locator(closeSelector).first();
|
|
117
|
+
await closeElement.focus();
|
|
118
|
+
await page.keyboard.press("Escape");
|
|
119
|
+
await page.waitForTimeout(200);
|
|
120
|
+
if (componentContract.selectors.input) {
|
|
121
|
+
const inputElement = page.locator(componentContract.selectors.input).first();
|
|
122
|
+
await inputElement.clear();
|
|
123
|
+
await page.waitForTimeout(50);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
110
127
|
}
|
|
111
128
|
for (const act of action) {
|
|
129
|
+
if (act.type === "focus") {
|
|
130
|
+
const focusSelector = componentContract.selectors[act.target];
|
|
131
|
+
if (!focusSelector) {
|
|
132
|
+
failures.push(`Selector for focus target ${act.target} not found.`);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
await page.locator(focusSelector).first().focus();
|
|
136
|
+
await page.waitForTimeout(50);
|
|
137
|
+
}
|
|
138
|
+
if (act.type === "type" && act.value) {
|
|
139
|
+
const typeSelector = componentContract.selectors[act.target];
|
|
140
|
+
if (!typeSelector) {
|
|
141
|
+
failures.push(`Selector for type target ${act.target} not found.`);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
await page.locator(typeSelector).first().fill(act.value);
|
|
145
|
+
await page.waitForTimeout(50);
|
|
146
|
+
}
|
|
112
147
|
if (act.type === "click") {
|
|
113
148
|
if (act.target === "document") {
|
|
114
149
|
await page.mouse.click(10, 10);
|
|
150
|
+
} else if (act.target === "relative" && act.relativeTarget) {
|
|
151
|
+
const relativeSelector = componentContract.selectors.relative;
|
|
152
|
+
if (!relativeSelector) {
|
|
153
|
+
failures.push(`Relative selector not defined for click action.`);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
|
|
157
|
+
if (!relativeElement) {
|
|
158
|
+
failures.push(`Could not resolve relative target ${act.relativeTarget} for click.`);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
await relativeElement.click();
|
|
162
|
+
await page.waitForTimeout(200);
|
|
115
163
|
} else {
|
|
116
164
|
const actionSelector = componentContract.selectors[act.target];
|
|
117
165
|
if (!actionSelector) {
|
|
@@ -160,6 +208,30 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
160
208
|
await target.press(keyValue);
|
|
161
209
|
}
|
|
162
210
|
}
|
|
211
|
+
if (act.type === "hover") {
|
|
212
|
+
if (act.target === "relative" && act.relativeTarget) {
|
|
213
|
+
const relativeSelector = componentContract.selectors.relative;
|
|
214
|
+
if (!relativeSelector) {
|
|
215
|
+
failures.push(`Relative selector not defined for hover action.`);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
|
|
219
|
+
if (!relativeElement) {
|
|
220
|
+
failures.push(`Could not resolve relative target ${act.relativeTarget} for hover.`);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
await relativeElement.hover();
|
|
224
|
+
await page.waitForTimeout(50);
|
|
225
|
+
} else {
|
|
226
|
+
const hoverSelector = componentContract.selectors[act.target];
|
|
227
|
+
if (!hoverSelector) {
|
|
228
|
+
failures.push(`Selector for hover target ${act.target} not found.`);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
await page.locator(hoverSelector).first().hover();
|
|
232
|
+
await page.waitForTimeout(50);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
163
235
|
await page.waitForTimeout(100);
|
|
164
236
|
}
|
|
165
237
|
for (const assertion of assertions) {
|
|
@@ -170,11 +242,12 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
170
242
|
failures.push("Relative selector is not defined in the contract.");
|
|
171
243
|
continue;
|
|
172
244
|
}
|
|
173
|
-
|
|
174
|
-
|
|
245
|
+
const relativeTargetValue = assertion.relativeTarget || assertion.expectedValue;
|
|
246
|
+
if (!relativeTargetValue) {
|
|
247
|
+
failures.push("Relative target or expected value is not defined.");
|
|
175
248
|
continue;
|
|
176
249
|
}
|
|
177
|
-
target = await resolveRelativeTarget(relativeSelector,
|
|
250
|
+
target = await resolveRelativeTarget(relativeSelector, relativeTargetValue);
|
|
178
251
|
} else {
|
|
179
252
|
const assertionSelector = componentContract.selectors[assertion.target];
|
|
180
253
|
if (!assertionSelector) {
|
|
@@ -205,12 +278,38 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
205
278
|
}
|
|
206
279
|
if (assertion.assertion === "toHaveAttribute" && assertion.attribute && assertion.expectedValue) {
|
|
207
280
|
const attributeValue = await target.getAttribute(assertion.attribute);
|
|
208
|
-
if (
|
|
281
|
+
if (assertion.expectedValue === "!empty") {
|
|
282
|
+
if (attributeValue && attributeValue.trim() !== "") {
|
|
283
|
+
passes.push(`${assertion.target} has non-empty "${assertion.attribute}". Test: "${dynamicTest.description}".`);
|
|
284
|
+
} else {
|
|
285
|
+
failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should not be empty, found "${attributeValue}".`);
|
|
286
|
+
}
|
|
287
|
+
} else if (attributeValue === assertion.expectedValue) {
|
|
209
288
|
passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
|
|
210
289
|
} else {
|
|
211
290
|
failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should be "${assertion.expectedValue}", found "${attributeValue}".`);
|
|
212
291
|
}
|
|
213
292
|
}
|
|
293
|
+
if (assertion.assertion === "toHaveValue") {
|
|
294
|
+
const inputValue = await target.inputValue().catch(() => "");
|
|
295
|
+
if (assertion.expectedValue === "!empty") {
|
|
296
|
+
if (inputValue && inputValue.trim() !== "") {
|
|
297
|
+
passes.push(`${assertion.target} has non-empty value. Test: "${dynamicTest.description}".`);
|
|
298
|
+
} else {
|
|
299
|
+
failures.push(assertion.failureMessage + ` ${assertion.target} value should not be empty, found "${inputValue}".`);
|
|
300
|
+
}
|
|
301
|
+
} else if (assertion.expectedValue === "") {
|
|
302
|
+
if (inputValue === "") {
|
|
303
|
+
passes.push(`${assertion.target} has empty value. Test: "${dynamicTest.description}".`);
|
|
304
|
+
} else {
|
|
305
|
+
failures.push(assertion.failureMessage + ` ${assertion.target} value should be empty, found "${inputValue}".`);
|
|
306
|
+
}
|
|
307
|
+
} else if (inputValue === assertion.expectedValue) {
|
|
308
|
+
passes.push(`${assertion.target} has expected value. Test: "${dynamicTest.description}".`);
|
|
309
|
+
} else {
|
|
310
|
+
failures.push(assertion.failureMessage + ` ${assertion.target} value should be "${assertion.expectedValue}", found "${inputValue}".`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
214
313
|
if (assertion.assertion === "toHaveFocus") {
|
|
215
314
|
const hasFocus = await target.evaluate((el) => el === document.activeElement);
|
|
216
315
|
if (hasFocus) {
|