aria-ease 2.8.2 → 2.8.3

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/cli.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import "./chunk-JSBRDJBE.js";
2
3
 
3
4
  // src/utils/cli/cli.ts
4
5
  import { Command } from "commander";
@@ -6,248 +7,6 @@ import chalk from "chalk";
6
7
  import path2 from "path";
7
8
  import fs2 from "fs-extra";
8
9
 
9
- // src/utils/audit/src/audit/audit.js
10
- import AxeBuilder from "@axe-core/playwright";
11
- import { chromium } from "playwright";
12
- async function runAudit(url, options) {
13
- let browser;
14
- const timeout = options?.timeout || 6e4;
15
- const waitUntil = options?.waitUntil || "domcontentloaded";
16
- try {
17
- browser = await chromium.launch({ headless: true });
18
- const context = await browser.newContext();
19
- const page = await context.newPage();
20
- await page.goto(url, { waitUntil, timeout });
21
- const axe2 = new AxeBuilder({ page });
22
- const axeResults = await axe2.analyze();
23
- return axeResults;
24
- } catch (error) {
25
- if (error instanceof Error) {
26
- if (error.message.includes("Executable doesn't exist")) {
27
- console.error("\n\u274C Playwright browsers not found!\n");
28
- console.log("\u{1F4E6} First-time setup required:");
29
- console.log(" Run: npx playwright install chromium\n");
30
- console.log("\u{1F4A1} This downloads the browser needed for auditing (~200MB)");
31
- console.log(" You only need to do this once.\n");
32
- } else if (error.message.includes("page.goto: net::ERR_CONNECTION_REFUSED")) {
33
- console.error("\n\u274C Server Not Running!\n");
34
- console.log(" Make sure your server is running before auditing URL");
35
- console.log(" Run: npm run dev # or your start command");
36
- } else if (error.message.includes("page.goto: Protocol error (Page.navigate): Cannot navigate to invalid URL")) {
37
- console.error("\n\u274C Cannot audit invalid URL\n");
38
- } else {
39
- console.error("\u274C Audit error:", error.message);
40
- console.log(" Make sure you provide a valid URL");
41
- }
42
- } else {
43
- console.error("\u274C Audit error (non-Error):", String(error));
44
- }
45
- throw error;
46
- } finally {
47
- if (browser)
48
- await browser.close();
49
- }
50
- }
51
-
52
- // src/utils/audit/src/formatters/formatters.js
53
- function formatResults(allResults, format) {
54
- switch (format) {
55
- case "json":
56
- return JSON.stringify(allResults.flatMap(({ url, result }) => result ? result.violations.flatMap((v) => v.nodes.map((n) => ({
57
- URL: url,
58
- Rule: v.id,
59
- Impact: v.impact,
60
- Description: v.description,
61
- Target: n.target,
62
- FailureSummary: n.failureSummary
63
- }))) : []), null, 2);
64
- case "csv":
65
- return toCSV(allResults);
66
- case "html":
67
- return toHTML(allResults);
68
- default:
69
- return "";
70
- }
71
- }
72
- function toCSV(allResults) {
73
- const rows = ["URL,Rule,Impact,Description,Target,FailureSummary"];
74
- allResults.forEach(({ url, result }) => {
75
- if (result) {
76
- result.violations.forEach((v) => {
77
- v.nodes.forEach((n) => {
78
- rows.push(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 ?? ""));
79
- });
80
- });
81
- }
82
- });
83
- return rows.join("\n");
84
- }
85
- function escapeCSV(value) {
86
- const s = String(value ?? "");
87
- return `"${s.replace(/"/g, '""')}"`;
88
- }
89
- function toHTML(allResults) {
90
- const summary = {
91
- pagesAudited: 0,
92
- pagesWithViolations: 0,
93
- totalViolations: 0,
94
- distinctRules: /* @__PURE__ */ new Set(),
95
- impactCounts: /* @__PURE__ */ new Map()
96
- };
97
- allResults.forEach(({ result }) => {
98
- if (!result)
99
- return;
100
- summary.pagesAudited++;
101
- const pageViolations = result.violations.reduce((acc, v) => {
102
- const nodesCount = (v.nodes || []).length;
103
- if (nodesCount > 0) {
104
- summary.distinctRules.add(v.id);
105
- summary.totalViolations += nodesCount;
106
- acc += nodesCount;
107
- const impact = String(v.impact ?? "unknown");
108
- summary.impactCounts.set(impact, (summary.impactCounts.get(impact) || 0) + nodesCount);
109
- }
110
- return acc;
111
- }, 0);
112
- if (pageViolations > 0)
113
- summary.pagesWithViolations++;
114
- });
115
- const rows = [];
116
- allResults.forEach(({ url, result }) => {
117
- if (!result)
118
- return;
119
- result.violations.forEach((v) => {
120
- v.nodes.forEach((n) => {
121
- const target = Array.isArray(n.target) ? n.target.join("; ") : String(n.target);
122
- rows.push(`
123
- <tr>
124
- <td class="nowrap">${escapeHTML(url)}</td>
125
- <td class="nowrap">${escapeHTML(v.id)}</td>
126
- <td class="impact ${escapeClass(String(v.impact ?? "unknown"))}">${escapeHTML(String(v.impact ?? ""))}</td>
127
- <td class="desc">${escapeHTML(v.description ?? "")}</td>
128
- <td class="target"><code>${escapeHTML(target)}</code></td>
129
- <td class="fail">${escapeHTML(n.failureSummary ?? "").split(/\r?\n/).join("<br/>")}</td>
130
- </tr>
131
- `);
132
- });
133
- });
134
- });
135
- const impactSummary = Array.from(summary.impactCounts.entries()).map(([impact, count]) => `<li><strong class="impact ${escapeClass(impact)}">${escapeHTML(impact)}</strong>: ${count}</li>`).join("\n");
136
- const d = /* @__PURE__ */ new Date();
137
- const pad = (n) => String(n).padStart(2, "0");
138
- const reportDateTime = `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
139
- const headerSummary = `
140
- <section class="summary">
141
- <h2>Report summary</h2>
142
- <ul>
143
- <li><strong>Date:</strong> ${reportDateTime}</li>
144
- <li><strong>Pages audited:</strong> ${summary.pagesAudited}</li>
145
- <li><strong>Pages with violations:</strong> ${summary.pagesWithViolations}</li>
146
- <li><strong>Total violations:</strong> ${summary.totalViolations}</li>
147
- <li><strong>Distinct rules:</strong> ${summary.distinctRules.size}</li>
148
- </ul>
149
- <div class="impact-summary">
150
- <h3>By impact</h3>
151
- <ul class="summary-list">
152
- ${impactSummary || "<li>None</li>"}
153
- </ul>
154
- </div>
155
- </section>
156
- `.trim();
157
- const html = `
158
- <!DOCTYPE html>
159
- <html lang="en">
160
- <head>
161
- <meta charset="utf-8"/>
162
- <title>Aria-Ease Accessibility Audit Report</title>
163
- <meta name="viewport" content="width=device-width, initial-scale=1"/>
164
- <style>
165
- :root{
166
- --bg:#ffffff; --muted:#6b7280; --border:#e6e9ee;
167
- --impact-critical: red; --impact-moderate:#fff4dd; --impact-serious:rgb(255, 123, 0);
168
- }
169
- body{font-family:Inter,ui-sans-serif,system-ui,Segoe UI,Roboto,Helvetica,Arial; background:var(--bg); color:#111827; padding:24px; line-height:1.4}
170
- h1{margin:0 0 8px}
171
- .summary{background:#f8fafc;border:1px solid var(--border);padding:12px 16px;border-radius:8px;margin-bottom:18px}
172
- .summary ul{margin:6px 0 0 0;padding:0 18px}
173
- .impact-summary h3{margin:12px 0 6px}
174
- table{width:100%; border-collapse:collapse; margin-top:12px}
175
- th,td{border:1px solid var(--border); padding:10px; text-align:left; vertical-align:top}
176
- th{background:#f3f4f6; font-weight:600; position:sticky; top:0; z-index:1}
177
- .nowrap{white-space:nowrap}
178
- .target code{font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, "Roboto Mono", "Courier New", monospace; white-space:pre-wrap}
179
- .desc{max-width:380px}
180
- tr:nth-child(even){background:#fbfbfb}
181
- td.fail{color:#7b1e1e}
182
- .impact.critical{background:var(--impact-critical); font-weight:600}
183
- .impact.moderate{background:var(--impact-moderate); font-weight:600}
184
- .impact.serious{background:var(--impact-serious); font-weight:600}
185
- @media (max-width:900px){
186
- .desc{max-width:200px}
187
- table, thead, tbody, th, td, tr{display:block}
188
- thead{display:none}
189
- tr{margin-bottom:10px; border: 1px solid var(--border);}
190
- td{border:1px solid var(--border); padding:6px}
191
- td::before{font-weight:600; display:inline-block; width:120px}
192
- }
193
- .summary-list strong,
194
- .summary-list li {
195
- padding: 2px 4px;
196
- }
197
- </style>
198
- </head>
199
- <body>
200
- <h1>Aria-Ease Accessibility Audit Report</h1>
201
- ${headerSummary}
202
- <table>
203
- <thead>
204
- <tr>
205
- <th>URL</th><th>Rule</th><th>Impact</th><th>Description</th><th>Target</th><th>FailureSummary</th>
206
- </tr>
207
- </thead>
208
- <tbody>
209
- ${rows.join("\n") || '<tr><td colspan="6"><em>No violations found.</em></td></tr>'}
210
- </tbody>
211
- </table>
212
- </body>
213
- </html>
214
- `.trim();
215
- return html;
216
- }
217
- function escapeHTML(str) {
218
- return String(str ?? "").replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
219
- }
220
- function escapeClass(s) {
221
- return String(s ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-");
222
- }
223
-
224
- // src/utils/test/src/test.ts
225
- import { axe } from "jest-axe";
226
- var runTest = async () => {
227
- };
228
- if (typeof window === "undefined") {
229
- runTest = async () => {
230
- console.log(`\u{1F680} Running component accessibility tests...
231
- `);
232
- const { exec } = await import("child_process");
233
- exec(
234
- `npx vitest --run --reporter verbose`,
235
- { cwd: process.cwd() },
236
- (error, stdout, stderr) => {
237
- if (stdout) {
238
- console.log(stdout);
239
- }
240
- if (stderr) {
241
- console.error(stderr);
242
- }
243
- if (error && error.code) {
244
- process.exit(error.code);
245
- }
246
- }
247
- );
248
- };
249
- }
250
-
251
10
  // src/utils/cli/configLoader.js
252
11
  import path from "path";
253
12
  import fs from "fs-extra";
@@ -369,6 +128,8 @@ var program = new Command();
369
128
  program.name("aria-ease").description("Run accessibility tests and audits").version("2.2.3");
370
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) => {
371
130
  console.log(chalk.cyanBright("\u{1F680} Starting accessibility audit...\n"));
131
+ const { runAudit } = await import("./audit-XABLAI36.js");
132
+ const { formatResults } = await import("./formatters-2RPHPXW2.js");
372
133
  const { config, configPath, errors } = await loadConfig(process.cwd());
373
134
  if (configPath) {
374
135
  console.log(chalk.green(`\u2705 Loaded config from ${path2.basename(configPath)}
@@ -442,7 +203,8 @@ program.command("audit").description("Run axe-core powered accessibility audit o
442
203
  }
443
204
  console.log(chalk.green("\n\u{1F389} All audits completed."));
444
205
  });
445
- program.command("test").description("Run core a11y accessibility standard tests on UI components").action(() => {
206
+ program.command("test").description("Run core a11y accessibility standard tests on UI components").action(async () => {
207
+ const { runTest } = await import("./test-S2U633GD.js");
446
208
  runTest();
447
209
  });
448
210
  program.command("help").description("Display help information").action(() => {
@@ -25,8 +25,11 @@ async function runContractTestsPlaywright(componentName, url) {
25
25
  browser = await chromium.launch({ headless: true });
26
26
  const context = await browser.newContext();
27
27
  const page = await context.newPage();
28
- await page.goto(url, { waitUntil: "networkidle" });
29
- await page.waitForSelector(componentContract.selectors.trigger, { timeout: 3e4 });
28
+ await page.goto(url, {
29
+ waitUntil: "domcontentloaded",
30
+ timeout: 6e4
31
+ });
32
+ await page.waitForSelector(componentContract.selectors.trigger, { timeout: 6e4 });
30
33
  async function resolveRelativeTarget(selector, relative) {
31
34
  const items = await page.locator(selector).all();
32
35
  switch (relative) {
@@ -25,8 +25,11 @@ async function runContractTestsPlaywright(componentName, url) {
25
25
  browser = await chromium.launch({ headless: true });
26
26
  const context = await browser.newContext();
27
27
  const page = await context.newPage();
28
- await page.goto(url, { waitUntil: "networkidle" });
29
- await page.waitForSelector(componentContract.selectors.trigger, { timeout: 9e4 });
28
+ await page.goto(url, {
29
+ waitUntil: "domcontentloaded",
30
+ timeout: 6e4
31
+ });
32
+ await page.waitForSelector(componentContract.selectors.trigger, { timeout: 6e4 });
30
33
  async function resolveRelativeTarget(selector, relative) {
31
34
  const items = await page.locator(selector).all();
32
35
  switch (relative) {
@@ -148,6 +151,11 @@ async function runContractTestsPlaywright(componentName, url) {
148
151
  continue;
149
152
  }
150
153
  const target = page.locator(keypressSelector).first();
154
+ const elementCount = await target.count();
155
+ if (elementCount === 0) {
156
+ reporter.reportTest(dynamicTest, "skip", `Skipping test - ${act.target} element not found (optional submenu test)`);
157
+ break;
158
+ }
151
159
  await target.press(keyValue);
152
160
  }
153
161
  }
package/dist/index.cjs CHANGED
@@ -9419,8 +9419,11 @@ async function runContractTestsPlaywright(componentName, url) {
9419
9419
  browser = await import_playwright.chromium.launch({ headless: true });
9420
9420
  const context = await browser.newContext();
9421
9421
  const page = await context.newPage();
9422
- await page.goto(url, { waitUntil: "networkidle" });
9423
- await page.waitForSelector(componentContract.selectors.trigger, { timeout: 3e4 });
9422
+ await page.goto(url, {
9423
+ waitUntil: "domcontentloaded",
9424
+ timeout: 6e4
9425
+ });
9426
+ await page.waitForSelector(componentContract.selectors.trigger, { timeout: 6e4 });
9424
9427
  async function resolveRelativeTarget(selector, relative) {
9425
9428
  const items = await page.locator(selector).all();
9426
9429
  switch (relative) {
@@ -9542,6 +9545,11 @@ async function runContractTestsPlaywright(componentName, url) {
9542
9545
  continue;
9543
9546
  }
9544
9547
  const target = page.locator(keypressSelector).first();
9548
+ const elementCount = await target.count();
9549
+ if (elementCount === 0) {
9550
+ reporter.reportTest(dynamicTest, "skip", `Skipping test - ${act.target} element not found (optional submenu test)`);
9551
+ break;
9552
+ }
9545
9553
  await target.press(keyValue);
9546
9554
  }
9547
9555
  }
package/dist/index.js CHANGED
@@ -13171,7 +13171,7 @@ async function testUiComponent(componentName, component, url) {
13171
13171
  let contract;
13172
13172
  if (url) {
13173
13173
  console.log(`\u{1F3AD} Running Playwright E2E tests on ${url}`);
13174
- const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-YNHMLHQ2.js");
13174
+ const { runContractTestsPlaywright } = await import("./contractTestRunnerPlaywright-AJ2DOOJT.js");
13175
13175
  contract = await runContractTestsPlaywright(componentName, url);
13176
13176
  } else {
13177
13177
  console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
@@ -21,8 +21,11 @@ async function runContractTestsPlaywright(componentName, url) {
21
21
  browser = await chromium.launch({ headless: true });
22
22
  const context = await browser.newContext();
23
23
  const page = await context.newPage();
24
- await page.goto(url, { waitUntil: "networkidle" });
25
- await page.waitForSelector(componentContract.selectors.trigger, { timeout: 5e3 });
24
+ await page.goto(url, {
25
+ waitUntil: "domcontentloaded",
26
+ timeout: 6e4
27
+ });
28
+ await page.waitForSelector(componentContract.selectors.trigger, { timeout: 6e4 });
26
29
  async function resolveRelativeTarget(selector, relative) {
27
30
  const items = await page.locator(selector).all();
28
31
  switch (relative) {
@@ -21,8 +21,11 @@ async function runContractTestsPlaywright(componentName, url) {
21
21
  browser = await chromium.launch({ headless: true });
22
22
  const context = await browser.newContext();
23
23
  const page = await context.newPage();
24
- await page.goto(url, { waitUntil: "networkidle" });
25
- await page.waitForSelector(componentContract.selectors.trigger, { timeout: 3e4 });
24
+ await page.goto(url, {
25
+ waitUntil: "domcontentloaded",
26
+ timeout: 6e4
27
+ });
28
+ await page.waitForSelector(componentContract.selectors.trigger, { timeout: 6e4 });
26
29
  async function resolveRelativeTarget(selector, relative) {
27
30
  const items = await page.locator(selector).all();
28
31
  switch (relative) {
@@ -144,6 +147,11 @@ async function runContractTestsPlaywright(componentName, url) {
144
147
  continue;
145
148
  }
146
149
  const target = page.locator(keypressSelector).first();
150
+ const elementCount = await target.count();
151
+ if (elementCount === 0) {
152
+ reporter.reportTest(dynamicTest, "skip", `Skipping test - ${act.target} element not found (optional submenu test)`);
153
+ break;
154
+ }
147
155
  await target.press(keyValue);
148
156
  }
149
157
  }
@@ -9257,8 +9257,11 @@ async function runContractTestsPlaywright(componentName, url) {
9257
9257
  browser = await playwright.chromium.launch({ headless: true });
9258
9258
  const context = await browser.newContext();
9259
9259
  const page = await context.newPage();
9260
- await page.goto(url, { waitUntil: "networkidle" });
9261
- await page.waitForSelector(componentContract.selectors.trigger, { timeout: 3e4 });
9260
+ await page.goto(url, {
9261
+ waitUntil: "domcontentloaded",
9262
+ timeout: 6e4
9263
+ });
9264
+ await page.waitForSelector(componentContract.selectors.trigger, { timeout: 6e4 });
9262
9265
  async function resolveRelativeTarget(selector, relative) {
9263
9266
  const items = await page.locator(selector).all();
9264
9267
  switch (relative) {
@@ -9380,6 +9383,11 @@ async function runContractTestsPlaywright(componentName, url) {
9380
9383
  continue;
9381
9384
  }
9382
9385
  const target = page.locator(keypressSelector).first();
9386
+ const elementCount = await target.count();
9387
+ if (elementCount === 0) {
9388
+ reporter.reportTest(dynamicTest, "skip", `Skipping test - ${act.target} element not found (optional submenu test)`);
9389
+ break;
9390
+ }
9383
9391
  await target.press(keyValue);
9384
9392
  }
9385
9393
  }
@@ -12524,7 +12524,7 @@ async function testUiComponent(componentName, component, url) {
12524
12524
  let contract;
12525
12525
  if (url) {
12526
12526
  console.log(`\u{1F3AD} Running Playwright E2E tests on ${url}`);
12527
- const { runContractTestsPlaywright } = await import('./contractTestRunnerPlaywright-YNHMLHQ2.js');
12527
+ const { runContractTestsPlaywright } = await import('./contractTestRunnerPlaywright-AJ2DOOJT.js');
12528
12528
  contract = await runContractTestsPlaywright(componentName, url);
12529
12529
  } else {
12530
12530
  console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aria-ease",
3
- "version": "2.8.2",
3
+ "version": "2.8.3",
4
4
  "description": "Out-of-the-box accessibility utility package to develop production ready applications.",
5
5
  "main": "dist/index.cjs",
6
6
  "type": "module",
@@ -1,213 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
- }) : x)(function(x) {
10
- if (typeof require !== "undefined") return require.apply(this, arguments);
11
- throw Error('Dynamic require of "' + x + '" is not supported');
12
- });
13
- var __commonJS = (cb, mod) => function __require2() {
14
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
15
- };
16
- var __copyProps = (to, from, except, desc) => {
17
- if (from && typeof from === "object" || typeof from === "function") {
18
- for (let key of __getOwnPropNames(from))
19
- if (!__hasOwnProp.call(to, key) && key !== except)
20
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
- }
22
- return to;
23
- };
24
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
- // If the importer is in node compatibility mode or this is not an ESM
26
- // file that has been converted to a CommonJS file using a Babel-
27
- // compatible transform (i.e. "__esModule" has not been set), then set
28
- // "default" to the CommonJS "module.exports" for node compatibility.
29
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
- mod
31
- ));
32
-
33
- // src/utils/test/contract/contract.json
34
- var contract_default = {
35
- menu: {
36
- path: "./contracts/MenuContract.json",
37
- component: "menu"
38
- }
39
- };
40
-
41
- // src/utils/test/contract/ContractReporter.ts
42
- var ContractReporter = class {
43
- startTime = 0;
44
- componentName = "";
45
- staticPasses = 0;
46
- staticFailures = 0;
47
- dynamicResults = [];
48
- totalTests = 0;
49
- skipped = 0;
50
- isPlaywright = false;
51
- constructor(isPlaywright = false) {
52
- this.isPlaywright = isPlaywright;
53
- }
54
- log(message) {
55
- process.stderr.write(message + "\n");
56
- }
57
- start(componentName, totalTests) {
58
- this.startTime = Date.now();
59
- this.componentName = componentName;
60
- this.totalTests = totalTests;
61
- const mode = this.isPlaywright ? "Playwright (Real Browser)" : "jsdom (Fast)";
62
- this.log(`
63
- ${"\u2550".repeat(60)}`);
64
- this.log(`\u{1F50D} Testing ${componentName} Component - ${mode}`);
65
- this.log(`${"\u2550".repeat(60)}
66
- `);
67
- }
68
- reportStatic(passes, failures) {
69
- this.staticPasses = passes;
70
- this.staticFailures = failures;
71
- const icon = failures === 0 ? "\u2705" : "\u274C";
72
- const status = failures === 0 ? "PASS" : "FAIL";
73
- this.log(`${icon} Static ARIA Tests: ${status}`);
74
- this.log(` ${passes}/${passes + failures} required attributes present
75
- `);
76
- }
77
- /**
78
- * Report individual dynamic test result
79
- */
80
- reportTest(test, status, failureMessage) {
81
- const result = {
82
- description: test.description,
83
- status,
84
- failureMessage
85
- };
86
- if (status === "skip" && test.requiresBrowser) {
87
- result.skipReason = "Requires real browser (addEventListener events)";
88
- }
89
- this.dynamicResults.push(result);
90
- const icons = { pass: "\u2713", fail: "\u2717", skip: "\u25CB" };
91
- this.log(` ${icons[status]} ${test.description}`);
92
- if (status === "skip" && !this.isPlaywright) {
93
- this.log(` \u21B3 Skipped in jsdom (runs in Playwright)`);
94
- }
95
- if (status === "fail" && failureMessage) {
96
- this.log(` \u21B3 ${failureMessage}`);
97
- }
98
- }
99
- /**
100
- * Report all failures with actionable context
101
- */
102
- reportFailures(failures) {
103
- if (failures.length === 0) return;
104
- this.log(`
105
- ${"\u2500".repeat(60)}`);
106
- this.log(`\u274C Failures (${failures.length}):
107
- `);
108
- failures.forEach((failure, index) => {
109
- this.log(`${index + 1}. ${failure}`);
110
- if (failure.includes("aria-")) {
111
- this.log(` \u{1F4A1} Add the missing ARIA attribute to improve screen reader support`);
112
- } else if (failure.includes("focus")) {
113
- this.log(` \u{1F4A1} Check keyboard event handlers and focus management`);
114
- } else if (failure.includes("visible")) {
115
- this.log(` \u{1F4A1} Verify display/visibility styles and state management`);
116
- }
117
- this.log("");
118
- });
119
- }
120
- /**
121
- * Report skipped tests with helpful context
122
- */
123
- reportSkipped() {
124
- if (this.skipped === 0 || this.isPlaywright) return;
125
- const skippedTests = this.dynamicResults.filter((r) => r.status === "skip");
126
- this.log(`
127
- ${"\u2500".repeat(60)}`);
128
- this.log(`\u2139\uFE0F Skipped Tests (${this.skipped}):
129
- `);
130
- this.log(`These tests use native keyboard events via addEventListener,`);
131
- this.log(`which jsdom cannot simulate. They run successfully in Playwright.
132
- `);
133
- skippedTests.forEach((test, index) => {
134
- this.log(`${index + 1}. ${test.description}`);
135
- });
136
- this.log(`
137
- \u{1F4A1} Run with Playwright for full validation:`);
138
- this.log(` testUiComponent('${this.componentName}', component, 'http://localhost:5173/')
139
- `);
140
- }
141
- /**
142
- * Generate final summary with statistics
143
- */
144
- summary(failures) {
145
- const duration = Date.now() - this.startTime;
146
- const dynamicPasses = this.dynamicResults.filter((r) => r.status === "pass").length;
147
- const dynamicFailures = this.dynamicResults.filter((r) => r.status === "fail").length;
148
- this.skipped = this.dynamicResults.filter((r) => r.status === "skip").length;
149
- const totalPasses = this.staticPasses + dynamicPasses;
150
- const totalFailures = this.staticFailures + dynamicFailures;
151
- const totalRun = totalPasses + totalFailures;
152
- if (failures.length > 0) {
153
- this.reportFailures(failures);
154
- }
155
- this.reportSkipped();
156
- this.log(`
157
- ${"\u2550".repeat(60)}`);
158
- this.log(`\u{1F4CA} Summary
159
- `);
160
- if (totalFailures === 0 && this.skipped === 0) {
161
- this.log(`\u2705 All ${totalRun} tests passed!`);
162
- this.log(` ${this.componentName} component meets APG and WCAG guidelines \u2713`);
163
- } else if (totalFailures === 0) {
164
- this.log(`\u2705 ${totalPasses}/${totalRun} tests passed`);
165
- this.log(`\u25CB ${this.skipped} tests skipped (jsdom limitation)`);
166
- this.log(` ${this.componentName} component works correctly`);
167
- } else {
168
- this.log(`\u274C ${totalFailures} test${totalFailures > 1 ? "s" : ""} failed`);
169
- this.log(`\u2705 ${totalPasses} test${totalPasses > 1 ? "s" : ""} passed`);
170
- if (this.skipped > 0) {
171
- this.log(`\u25CB ${this.skipped} test${this.skipped > 1 ? "s" : ""} skipped`);
172
- }
173
- }
174
- this.log(`\u23F1\uFE0F Duration: ${duration}ms`);
175
- this.log(`${"\u2550".repeat(60)}
176
- `);
177
- if (totalFailures > 0) {
178
- this.log(`\u{1F527} Next Steps:`);
179
- this.log(` 1. Review the failures above`);
180
- this.log(` 2. Fix ARIA attributes and keyboard handlers`);
181
- this.log(` 3. Re-run tests to verify fixes
182
- `);
183
- } else if (!this.isPlaywright && this.skipped > 0) {
184
- this.log(`\u2728 Optional: Run Playwright tests for complete validation
185
- `);
186
- }
187
- return {
188
- passes: totalPasses,
189
- failures: totalFailures,
190
- skipped: this.skipped,
191
- duration
192
- };
193
- }
194
- /**
195
- * Report an error during test execution
196
- */
197
- error(message, context) {
198
- this.log(`
199
- \u274C Error: ${message}`);
200
- if (context) {
201
- this.log(` Context: ${context}`);
202
- }
203
- this.log("");
204
- }
205
- };
206
-
207
- export {
208
- __require,
209
- __commonJS,
210
- __toESM,
211
- contract_default,
212
- ContractReporter
213
- };
@@ -1,254 +0,0 @@
1
- import {
2
- ContractReporter,
3
- contract_default
4
- } from "./chunk-PCORWVIQ.js";
5
-
6
- // src/utils/test/contract/contractTestRunnerPlaywright.ts
7
- import { chromium } from "playwright";
8
- import { readFileSync } from "fs";
9
- async function runContractTestsPlaywright(componentName, url) {
10
- const reporter = new ContractReporter(true);
11
- const contractTyped = contract_default;
12
- const contractPath = contractTyped[componentName]?.path;
13
- if (!contractPath) {
14
- throw new Error(`Contract path not found for component: ${componentName}`);
15
- }
16
- const resolvedPath = new URL(contractPath, import.meta.url).pathname;
17
- const contractData = readFileSync(resolvedPath, "utf-8");
18
- const componentContract = JSON.parse(contractData);
19
- const totalTests = componentContract.static[0].assertions.length + componentContract.dynamic.length;
20
- reporter.start(componentName, totalTests);
21
- const failures = [];
22
- const passes = [];
23
- let browser = null;
24
- try {
25
- browser = await chromium.launch({ headless: true });
26
- const context = await browser.newContext();
27
- const page = await context.newPage();
28
- await page.goto(url, { waitUntil: "networkidle" });
29
- await page.waitForSelector(componentContract.selectors.trigger, { timeout: 5e3 });
30
- async function resolveRelativeTarget(selector, relative) {
31
- const items = await page.locator(selector).all();
32
- switch (relative) {
33
- case "first":
34
- return items[0];
35
- case "second":
36
- return items[1];
37
- case "last":
38
- return items[items.length - 1];
39
- case "next": {
40
- const currentIndex = await page.evaluate(([sel]) => {
41
- const items2 = Array.from(document.querySelectorAll(sel));
42
- return items2.indexOf(document.activeElement);
43
- }, [selector]);
44
- const nextIndex = (currentIndex + 1) % items.length;
45
- return items[nextIndex];
46
- }
47
- case "previous": {
48
- const currentIndex = await page.evaluate(([sel]) => {
49
- const items2 = Array.from(document.querySelectorAll(sel));
50
- return items2.indexOf(document.activeElement);
51
- }, [selector]);
52
- const prevIndex = (currentIndex - 1 + items.length) % items.length;
53
- return items[prevIndex];
54
- }
55
- default:
56
- return null;
57
- }
58
- }
59
- for (const test of componentContract.static[0]?.assertions || []) {
60
- if (test.target === "relative") continue;
61
- const targetSelector = componentContract.selectors[test.target];
62
- if (!targetSelector) {
63
- failures.push(`Selector for target ${test.target} not found.`);
64
- continue;
65
- }
66
- const target = page.locator(targetSelector).first();
67
- const exists = await target.count() > 0;
68
- if (!exists) {
69
- failures.push(`Target ${test.target} not found.`);
70
- continue;
71
- }
72
- if (!test.expectedValue) {
73
- const attributes = test.attribute.split(" | ");
74
- let hasAny = false;
75
- for (const attr of attributes) {
76
- const value = await target.getAttribute(attr.trim());
77
- if (value !== null) {
78
- hasAny = true;
79
- break;
80
- }
81
- }
82
- if (!hasAny) {
83
- failures.push(test.failureMessage + ` None of the attributes "${test.attribute}" are present.`);
84
- } else {
85
- passes.push(`At least one of the attributes "${test.attribute}" exists on the element.`);
86
- }
87
- } else {
88
- const attributeValue = await target.getAttribute(test.attribute);
89
- const expectedValues = test.expectedValue.split(" | ");
90
- if (!attributeValue || !expectedValues.includes(attributeValue)) {
91
- failures.push(test.failureMessage + ` Attribute value does not match expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);
92
- } else {
93
- passes.push(`Attribute value matches expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);
94
- }
95
- }
96
- }
97
- for (const dynamicTest of componentContract.dynamic || []) {
98
- const { action, assertions } = dynamicTest;
99
- const failuresBeforeTest = failures.length;
100
- const containerElement = page.locator(componentContract.selectors.container).first();
101
- const triggerElement = page.locator(componentContract.selectors.trigger).first();
102
- const isContainerVisible = await containerElement.isVisible();
103
- if (isContainerVisible) {
104
- await triggerElement.click();
105
- await page.waitForTimeout(50);
106
- }
107
- for (const act of action) {
108
- if (act.type === "click") {
109
- if (act.target === "document") {
110
- await page.mouse.click(10, 10);
111
- } else {
112
- const actionSelector = componentContract.selectors[act.target];
113
- if (!actionSelector) {
114
- failures.push(`Selector for action target ${act.target} not found.`);
115
- continue;
116
- }
117
- await page.locator(actionSelector).first().click();
118
- await page.waitForTimeout(200);
119
- }
120
- }
121
- if (act.type === "keypress" && act.key) {
122
- const keyMap = {
123
- "Space": "Space",
124
- "Enter": "Enter",
125
- "Escape": "Escape",
126
- "Arrow Up": "ArrowUp",
127
- "Arrow Down": "ArrowDown",
128
- "Arrow Left": "ArrowLeft",
129
- "Arrow Right": "ArrowRight",
130
- "Home": "Home",
131
- "End": "End",
132
- "Tab": "Tab"
133
- };
134
- let keyValue = keyMap[act.key] || act.key;
135
- if (keyValue === "Space") {
136
- keyValue = " ";
137
- } else if (keyValue.includes(" ")) {
138
- keyValue = keyValue.replace(/ /g, "");
139
- }
140
- if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
141
- await page.waitForTimeout(100);
142
- await page.keyboard.press(keyValue);
143
- await page.waitForTimeout(50);
144
- } else {
145
- const keypressSelector = componentContract.selectors[act.target];
146
- if (!keypressSelector) {
147
- failures.push(`Selector for keypress target ${act.target} not found.`);
148
- continue;
149
- }
150
- const target = page.locator(keypressSelector).first();
151
- await target.press(keyValue);
152
- }
153
- }
154
- await page.waitForTimeout(100);
155
- }
156
- for (const assertion of assertions) {
157
- let target;
158
- if (assertion.target === "relative") {
159
- const relativeSelector = componentContract.selectors.relative;
160
- if (!relativeSelector) {
161
- failures.push("Relative selector is not defined in the contract.");
162
- continue;
163
- }
164
- if (!assertion.expectedValue) {
165
- failures.push("Expected value for relative target is not defined.");
166
- continue;
167
- }
168
- target = await resolveRelativeTarget(relativeSelector, assertion.expectedValue);
169
- } else {
170
- const assertionSelector = componentContract.selectors[assertion.target];
171
- if (!assertionSelector) {
172
- failures.push(`Selector for assertion target ${assertion.target} not found.`);
173
- continue;
174
- }
175
- target = page.locator(assertionSelector).first();
176
- }
177
- if (!target) {
178
- failures.push(`Target ${assertion.target} not found.`);
179
- continue;
180
- }
181
- if (assertion.assertion === "toBeVisible") {
182
- const isVisible = await target.isVisible();
183
- if (isVisible) {
184
- passes.push(`${assertion.target} is visible as expected. Test: "${dynamicTest.description}".`);
185
- } else {
186
- failures.push(`${assertion.failureMessage}`);
187
- }
188
- }
189
- if (assertion.assertion === "notToBeVisible") {
190
- const isVisible = await target.isVisible();
191
- if (!isVisible) {
192
- passes.push(`${assertion.target} is not visible as expected. Test: "${dynamicTest.description}".`);
193
- } else {
194
- failures.push(assertion.failureMessage + ` ${assertion.target} is still visible.`);
195
- }
196
- }
197
- if (assertion.assertion === "toHaveAttribute" && assertion.attribute && assertion.expectedValue) {
198
- const attributeValue = await target.getAttribute(assertion.attribute);
199
- if (attributeValue === assertion.expectedValue) {
200
- passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
201
- } else {
202
- failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should be "${assertion.expectedValue}", found "${attributeValue}".`);
203
- }
204
- }
205
- if (assertion.assertion === "toHaveFocus") {
206
- const hasFocus = await target.evaluate((el) => el === document.activeElement);
207
- if (hasFocus) {
208
- passes.push(`${assertion.target} has focus as expected. Test: "${dynamicTest.description}".`);
209
- } else {
210
- failures.push(`${assertion.failureMessage}`);
211
- }
212
- }
213
- if (assertion.assertion === "toHaveRole" && assertion.expectedValue) {
214
- const roleValue = await target.getAttribute("role");
215
- if (roleValue === assertion.expectedValue) {
216
- passes.push(`${assertion.target} has role "${assertion.expectedValue}". Test: "${dynamicTest.description}".`);
217
- } else {
218
- failures.push(assertion.failureMessage + ` Expected role "${assertion.expectedValue}", found "${roleValue}".`);
219
- }
220
- }
221
- }
222
- const failuresAfterTest = failures.length;
223
- const testPassed = failuresAfterTest === failuresBeforeTest;
224
- const failureMessage = testPassed ? void 0 : failures[failures.length - 1];
225
- reporter.reportTest(dynamicTest, testPassed ? "pass" : "fail", failureMessage);
226
- }
227
- const staticPassed = componentContract.static[0].assertions.length;
228
- const staticFailed = 0;
229
- reporter.reportStatic(staticPassed, staticFailed);
230
- reporter.summary(failures);
231
- } catch (error) {
232
- if (error instanceof Error) {
233
- if (error.message.includes("Executable doesn't exist")) {
234
- console.error("\n\u274C Playwright browsers not found!\n");
235
- console.log("\u{1F4E6} Run: npx playwright install chromium\n");
236
- failures.push("Playwright browser not installed. Run: npx playwright install chromium");
237
- } else if (error.message.includes("net::ERR_CONNECTION_REFUSED")) {
238
- console.error("\n\u274C Cannot connect to dev server!\n");
239
- console.log(` Make sure your dev server is running at ${url}
240
- `);
241
- failures.push(`Dev server not running at ${url}`);
242
- } else {
243
- console.error("\u274C Playwright test error:", error.message);
244
- failures.push(`Test error: ${error.message}`);
245
- }
246
- }
247
- } finally {
248
- if (browser) await browser.close();
249
- }
250
- return { passes, failures };
251
- }
252
- export {
253
- runContractTestsPlaywright
254
- };
@@ -1,249 +0,0 @@
1
- import { ContractReporter, contract_default } from './chunk-SSBW5VAA.js';
2
- import { chromium } from 'playwright';
3
- import { readFileSync } from 'fs';
4
-
5
- async function runContractTestsPlaywright(componentName, url) {
6
- const reporter = new ContractReporter(true);
7
- const contractTyped = contract_default;
8
- const contractPath = contractTyped[componentName]?.path;
9
- if (!contractPath) {
10
- throw new Error(`Contract path not found for component: ${componentName}`);
11
- }
12
- const resolvedPath = new URL(contractPath, import.meta.url).pathname;
13
- const contractData = readFileSync(resolvedPath, "utf-8");
14
- const componentContract = JSON.parse(contractData);
15
- const totalTests = componentContract.static[0].assertions.length + componentContract.dynamic.length;
16
- reporter.start(componentName, totalTests);
17
- const failures = [];
18
- const passes = [];
19
- let browser = null;
20
- try {
21
- browser = await chromium.launch({ headless: true });
22
- const context = await browser.newContext();
23
- const page = await context.newPage();
24
- await page.goto(url, { waitUntil: "networkidle" });
25
- await page.waitForSelector(componentContract.selectors.trigger, { timeout: 9e4 });
26
- async function resolveRelativeTarget(selector, relative) {
27
- const items = await page.locator(selector).all();
28
- switch (relative) {
29
- case "first":
30
- return items[0];
31
- case "second":
32
- return items[1];
33
- case "last":
34
- return items[items.length - 1];
35
- case "next": {
36
- const currentIndex = await page.evaluate(([sel]) => {
37
- const items2 = Array.from(document.querySelectorAll(sel));
38
- return items2.indexOf(document.activeElement);
39
- }, [selector]);
40
- const nextIndex = (currentIndex + 1) % items.length;
41
- return items[nextIndex];
42
- }
43
- case "previous": {
44
- const currentIndex = await page.evaluate(([sel]) => {
45
- const items2 = Array.from(document.querySelectorAll(sel));
46
- return items2.indexOf(document.activeElement);
47
- }, [selector]);
48
- const prevIndex = (currentIndex - 1 + items.length) % items.length;
49
- return items[prevIndex];
50
- }
51
- default:
52
- return null;
53
- }
54
- }
55
- for (const test of componentContract.static[0]?.assertions || []) {
56
- if (test.target === "relative") continue;
57
- const targetSelector = componentContract.selectors[test.target];
58
- if (!targetSelector) {
59
- failures.push(`Selector for target ${test.target} not found.`);
60
- continue;
61
- }
62
- const target = page.locator(targetSelector).first();
63
- const exists = await target.count() > 0;
64
- if (!exists) {
65
- failures.push(`Target ${test.target} not found.`);
66
- continue;
67
- }
68
- if (!test.expectedValue) {
69
- const attributes = test.attribute.split(" | ");
70
- let hasAny = false;
71
- for (const attr of attributes) {
72
- const value = await target.getAttribute(attr.trim());
73
- if (value !== null) {
74
- hasAny = true;
75
- break;
76
- }
77
- }
78
- if (!hasAny) {
79
- failures.push(test.failureMessage + ` None of the attributes "${test.attribute}" are present.`);
80
- } else {
81
- passes.push(`At least one of the attributes "${test.attribute}" exists on the element.`);
82
- }
83
- } else {
84
- const attributeValue = await target.getAttribute(test.attribute);
85
- const expectedValues = test.expectedValue.split(" | ");
86
- if (!attributeValue || !expectedValues.includes(attributeValue)) {
87
- failures.push(test.failureMessage + ` Attribute value does not match expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);
88
- } else {
89
- passes.push(`Attribute value matches expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);
90
- }
91
- }
92
- }
93
- for (const dynamicTest of componentContract.dynamic || []) {
94
- const { action, assertions } = dynamicTest;
95
- const failuresBeforeTest = failures.length;
96
- const containerElement = page.locator(componentContract.selectors.container).first();
97
- const triggerElement = page.locator(componentContract.selectors.trigger).first();
98
- const isContainerVisible = await containerElement.isVisible();
99
- if (isContainerVisible) {
100
- await triggerElement.click();
101
- await page.waitForTimeout(50);
102
- }
103
- for (const act of action) {
104
- if (act.type === "click") {
105
- if (act.target === "document") {
106
- await page.mouse.click(10, 10);
107
- } else {
108
- const actionSelector = componentContract.selectors[act.target];
109
- if (!actionSelector) {
110
- failures.push(`Selector for action target ${act.target} not found.`);
111
- continue;
112
- }
113
- await page.locator(actionSelector).first().click();
114
- await page.waitForTimeout(200);
115
- }
116
- }
117
- if (act.type === "keypress" && act.key) {
118
- const keyMap = {
119
- "Space": "Space",
120
- "Enter": "Enter",
121
- "Escape": "Escape",
122
- "Arrow Up": "ArrowUp",
123
- "Arrow Down": "ArrowDown",
124
- "Arrow Left": "ArrowLeft",
125
- "Arrow Right": "ArrowRight",
126
- "Home": "Home",
127
- "End": "End",
128
- "Tab": "Tab"
129
- };
130
- let keyValue = keyMap[act.key] || act.key;
131
- if (keyValue === "Space") {
132
- keyValue = " ";
133
- } else if (keyValue.includes(" ")) {
134
- keyValue = keyValue.replace(/ /g, "");
135
- }
136
- if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
137
- await page.waitForTimeout(100);
138
- await page.keyboard.press(keyValue);
139
- await page.waitForTimeout(50);
140
- } else {
141
- const keypressSelector = componentContract.selectors[act.target];
142
- if (!keypressSelector) {
143
- failures.push(`Selector for keypress target ${act.target} not found.`);
144
- continue;
145
- }
146
- const target = page.locator(keypressSelector).first();
147
- await target.press(keyValue);
148
- }
149
- }
150
- await page.waitForTimeout(100);
151
- }
152
- for (const assertion of assertions) {
153
- let target;
154
- if (assertion.target === "relative") {
155
- const relativeSelector = componentContract.selectors.relative;
156
- if (!relativeSelector) {
157
- failures.push("Relative selector is not defined in the contract.");
158
- continue;
159
- }
160
- if (!assertion.expectedValue) {
161
- failures.push("Expected value for relative target is not defined.");
162
- continue;
163
- }
164
- target = await resolveRelativeTarget(relativeSelector, assertion.expectedValue);
165
- } else {
166
- const assertionSelector = componentContract.selectors[assertion.target];
167
- if (!assertionSelector) {
168
- failures.push(`Selector for assertion target ${assertion.target} not found.`);
169
- continue;
170
- }
171
- target = page.locator(assertionSelector).first();
172
- }
173
- if (!target) {
174
- failures.push(`Target ${assertion.target} not found.`);
175
- continue;
176
- }
177
- if (assertion.assertion === "toBeVisible") {
178
- const isVisible = await target.isVisible();
179
- if (isVisible) {
180
- passes.push(`${assertion.target} is visible as expected. Test: "${dynamicTest.description}".`);
181
- } else {
182
- failures.push(`${assertion.failureMessage}`);
183
- }
184
- }
185
- if (assertion.assertion === "notToBeVisible") {
186
- const isVisible = await target.isVisible();
187
- if (!isVisible) {
188
- passes.push(`${assertion.target} is not visible as expected. Test: "${dynamicTest.description}".`);
189
- } else {
190
- failures.push(assertion.failureMessage + ` ${assertion.target} is still visible.`);
191
- }
192
- }
193
- if (assertion.assertion === "toHaveAttribute" && assertion.attribute && assertion.expectedValue) {
194
- const attributeValue = await target.getAttribute(assertion.attribute);
195
- if (attributeValue === assertion.expectedValue) {
196
- passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
197
- } else {
198
- failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should be "${assertion.expectedValue}", found "${attributeValue}".`);
199
- }
200
- }
201
- if (assertion.assertion === "toHaveFocus") {
202
- const hasFocus = await target.evaluate((el) => el === document.activeElement);
203
- if (hasFocus) {
204
- passes.push(`${assertion.target} has focus as expected. Test: "${dynamicTest.description}".`);
205
- } else {
206
- failures.push(`${assertion.failureMessage}`);
207
- }
208
- }
209
- if (assertion.assertion === "toHaveRole" && assertion.expectedValue) {
210
- const roleValue = await target.getAttribute("role");
211
- if (roleValue === assertion.expectedValue) {
212
- passes.push(`${assertion.target} has role "${assertion.expectedValue}". Test: "${dynamicTest.description}".`);
213
- } else {
214
- failures.push(assertion.failureMessage + ` Expected role "${assertion.expectedValue}", found "${roleValue}".`);
215
- }
216
- }
217
- }
218
- const failuresAfterTest = failures.length;
219
- const testPassed = failuresAfterTest === failuresBeforeTest;
220
- const failureMessage = testPassed ? void 0 : failures[failures.length - 1];
221
- reporter.reportTest(dynamicTest, testPassed ? "pass" : "fail", failureMessage);
222
- }
223
- const staticPassed = componentContract.static[0].assertions.length;
224
- const staticFailed = 0;
225
- reporter.reportStatic(staticPassed, staticFailed);
226
- reporter.summary(failures);
227
- } catch (error) {
228
- if (error instanceof Error) {
229
- if (error.message.includes("Executable doesn't exist")) {
230
- console.error("\n\u274C Playwright browsers not found!\n");
231
- console.log("\u{1F4E6} Run: npx playwright install chromium\n");
232
- failures.push("Playwright browser not installed. Run: npx playwright install chromium");
233
- } else if (error.message.includes("net::ERR_CONNECTION_REFUSED")) {
234
- console.error("\n\u274C Cannot connect to dev server!\n");
235
- console.log(` Make sure your dev server is running at ${url}
236
- `);
237
- failures.push(`Dev server not running at ${url}`);
238
- } else {
239
- console.error("\u274C Playwright test error:", error.message);
240
- failures.push(`Test error: ${error.message}`);
241
- }
242
- }
243
- } finally {
244
- if (browser) await browser.close();
245
- }
246
- return { passes, failures };
247
- }
248
-
249
- export { runContractTestsPlaywright };