aria-ease 2.8.0 → 2.8.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.
Files changed (82) hide show
  1. package/bin/cli.js +3 -4
  2. package/dist/chunk-PCORWVIQ.js +213 -0
  3. package/dist/{chunk-4F6O5RKZ.js → chunk-SSBW5VAA.js} +0 -1
  4. package/dist/{contractTestRunnerPlaywright-FM6MK6DY.js → contractTestRunnerPlaywright-SE6TPWZZ.js} +1 -2
  5. package/{bin/contractTestRunnerPlaywright-2LQHVMXT.js → dist/contractTestRunnerPlaywright-YNHMLHQ2.js} +6 -178
  6. package/dist/contractTestRunnerPlaywright-ZY2T4UTV.js +254 -0
  7. package/dist/index.cjs +23 -8
  8. package/dist/index.d.cts +11 -14
  9. package/dist/index.d.ts +11 -14
  10. package/dist/index.js +24 -9
  11. package/dist/src/{Types.d-BbztRe-S.d.cts → Types.d-w1KLKLcA.d.cts} +8 -1
  12. package/dist/src/{Types.d-BbztRe-S.d.ts → Types.d-w1KLKLcA.d.ts} +8 -1
  13. package/dist/src/accordion/index.cjs +0 -2
  14. package/dist/src/accordion/index.d.cts +1 -1
  15. package/dist/src/accordion/index.d.ts +1 -1
  16. package/dist/src/accordion/index.js +0 -2
  17. package/dist/src/block/index.cjs +13 -5
  18. package/dist/src/block/index.d.cts +4 -3
  19. package/dist/src/block/index.d.ts +4 -3
  20. package/dist/src/block/index.js +14 -6
  21. package/dist/src/checkbox/index.cjs +0 -2
  22. package/dist/src/checkbox/index.d.cts +1 -1
  23. package/dist/src/checkbox/index.d.ts +1 -1
  24. package/dist/src/checkbox/index.js +0 -2
  25. package/dist/src/{chunk-DF4OR64G.js → chunk-TBJ6MIC7.js} +0 -2
  26. package/dist/src/menu/index.cjs +9 -4
  27. package/dist/src/menu/index.d.cts +4 -11
  28. package/dist/src/menu/index.d.ts +4 -11
  29. package/dist/src/menu/index.js +10 -5
  30. package/dist/src/radio/index.cjs +0 -2
  31. package/dist/src/radio/index.d.cts +1 -1
  32. package/dist/src/radio/index.d.ts +1 -1
  33. package/dist/src/radio/index.js +0 -2
  34. package/dist/src/toggle/index.cjs +0 -2
  35. package/dist/src/toggle/index.d.cts +1 -1
  36. package/dist/src/toggle/index.d.ts +1 -1
  37. package/dist/src/toggle/index.js +0 -2
  38. package/dist/src/utils/test/{chunk-UAS6V5MH.js → chunk-SSBW5VAA.js} +0 -2
  39. package/dist/src/utils/test/{contractTestRunnerPlaywright-IBC4FHWK.js → contractTestRunnerPlaywright-I36Y2NHA.js} +1 -3
  40. package/dist/src/utils/test/contractTestRunnerPlaywright-YNHMLHQ2.js +249 -0
  41. package/dist/src/utils/test/contractTestRunnerPlaywright-ZY2T4UTV.js +249 -0
  42. package/dist/src/utils/test/contracts/MenuContract.json +52 -8
  43. package/dist/src/utils/test/index.cjs +1 -3
  44. package/dist/src/utils/test/index.js +2 -4
  45. package/package.json +14 -13
  46. package/bin/cli.cjs +0 -475
  47. package/bin/cli.cjs.map +0 -1
  48. package/bin/cli.d.cts +0 -1
  49. package/bin/cli.d.ts +0 -1
  50. package/bin/cli.d.ts.map +0 -1
  51. package/bin/cli.js.map +0 -1
  52. package/bin/cli.ts +0 -122
  53. package/bin/configLoader.d.ts +0 -19
  54. package/bin/configLoader.d.ts.map +0 -1
  55. package/bin/configLoader.js +0 -155
  56. package/bin/configLoader.ts +0 -170
  57. package/bin/contractTestRunnerPlaywright-2LQHVMXT.js.map +0 -1
  58. package/dist/chunk-4F6O5RKZ.js.map +0 -1
  59. package/dist/contractTestRunnerPlaywright-FM6MK6DY.js.map +0 -1
  60. package/dist/index.cjs.map +0 -1
  61. package/dist/index.js.map +0 -1
  62. package/dist/src/accordion/index.cjs.map +0 -1
  63. package/dist/src/accordion/index.js.map +0 -1
  64. package/dist/src/block/index.cjs.map +0 -1
  65. package/dist/src/block/index.js.map +0 -1
  66. package/dist/src/checkbox/index.cjs.map +0 -1
  67. package/dist/src/checkbox/index.js.map +0 -1
  68. package/dist/src/chunk-CGC24XEF.js +0 -127
  69. package/dist/src/chunk-CGC24XEF.js.map +0 -1
  70. package/dist/src/chunk-DF4OR64G.js.map +0 -1
  71. package/dist/src/chunk-MNMWQWXH.js +0 -117
  72. package/dist/src/chunk-MNMWQWXH.js.map +0 -1
  73. package/dist/src/menu/index.cjs.map +0 -1
  74. package/dist/src/menu/index.js.map +0 -1
  75. package/dist/src/radio/index.cjs.map +0 -1
  76. package/dist/src/radio/index.js.map +0 -1
  77. package/dist/src/toggle/index.cjs.map +0 -1
  78. package/dist/src/toggle/index.js.map +0 -1
  79. package/dist/src/utils/test/chunk-UAS6V5MH.js.map +0 -1
  80. package/dist/src/utils/test/contractTestRunnerPlaywright-IBC4FHWK.js.map +0 -1
  81. package/dist/src/utils/test/index.cjs.map +0 -1
  82. package/dist/src/utils/test/index.js.map +0 -1
package/bin/cli.ts DELETED
@@ -1,122 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { Command } from "commander";
4
- import chalk from "chalk";
5
- import path from "path";
6
- import fs from "fs-extra";
7
- import { AxeResult } from "Types";
8
- import { runAudit } from "../src/utils/audit/src/audit/audit.js";
9
- import { formatResults } from "../src/utils/audit/src/formatters/formatters.js";
10
- import { runTest } from "../src/utils/test/index.js";
11
- import { loadConfig } from "./configLoader.js";
12
-
13
- const program = new Command();
14
-
15
- program.name('aria-ease').description('Run accessibility tests and audits').version('2.2.3');
16
-
17
- program.command('audit')
18
- .description('Run axe-core powered accessibility audit on webpages')
19
- .option('-u, --url <url>', 'Single URL to audit')
20
- .option('-f, --format <format>', 'Output format for the audit report: json | csv | html | all', 'all')
21
- .option('-o, --out <path>', 'Directory to save the audit report', './accessibility-reports/audit')
22
- .action(async (opts) => {
23
- console.log(chalk.cyanBright('🚀 Starting accessibility audit...\n'));
24
-
25
- // Load config with robust discovery and validation
26
- const { config, configPath, errors } = await loadConfig(process.cwd());
27
-
28
- if (configPath) {
29
- console.log(chalk.green(`✅ Loaded config from ${path.basename(configPath)}\n`));
30
- } else if (errors.length > 0) {
31
- console.log(chalk.red('❌ Config file errors:\n'));
32
- errors.forEach(err => console.log(chalk.red(` ${err}`)));
33
- console.log('');
34
- process.exit(1);
35
- } else {
36
- console.log(chalk.yellow('ℹ️ No config file found, using CLI options.\n'));
37
- }
38
-
39
- const urls: string[] = [];
40
- if(opts.url) urls.push(opts.url);
41
- if(config.audit?.urls && Array.isArray(config.audit.urls)) urls.push(...config.audit.urls);
42
-
43
- const format: string = (config.audit?.output && (config.audit.output as { format?: string }).format) || opts.format;
44
- if(!['json', 'csv', 'html', 'all'].includes(format)) {
45
- console.log(chalk.red('❌ Invalid format. Use "json", "csv", "html" or "all".'));
46
- process.exit(1);
47
- }
48
-
49
- if(urls.length === 0) {
50
- console.log(chalk.red('❌ No URLs provided. Use --url option or add "urls" in config file'));
51
- process.exit(1);
52
- }
53
-
54
- const allResults: { url: string, result?: AxeResult }[] = [];
55
- const auditOptions = {
56
- timeout: config.audit?.timeout,
57
- waitUntil: config.audit?.waitUntil
58
- };
59
-
60
- for (const url of urls) {
61
- console.log(chalk.yellow(`🔎 Auditing: ${url}`));
62
- try {
63
- const result: AxeResult = await runAudit(url, auditOptions);
64
- allResults.push({ url: url, result });
65
- console.log(chalk.green(`✅ Completed audit for ${url}\n`));
66
- } catch (error: unknown) {
67
- if(error instanceof Error && error.message) {
68
- console.log(chalk.red(`❌ Failed auditing ${url}: ${error.message}`));
69
- }
70
- }
71
- }
72
-
73
- const hasResults = allResults.some(r => r.result && r.result.violations && r.result.violations.length > 0);
74
- if (!hasResults) {
75
- const auditedCount = allResults.filter(r => r.result).length;
76
- if (auditedCount === 0) {
77
- console.log(chalk.red('❌ No pages were successfully audited.'));
78
- process.exit(1);
79
- }
80
- console.log(chalk.green('\n🎉 Great news! No static accessibility violations found!'));
81
- console.log(chalk.gray(` Audited ${auditedCount} page${auditedCount > 1 ? 's' : ''} successfully.\n`));
82
- process.exit(0);
83
- }
84
-
85
- async function createReport(format: string) {
86
- const formatted = formatResults(allResults, format);
87
-
88
- const out = (config.audit?.output && (config.audit.output as { out?: string }).out) || opts.out;
89
-
90
- await fs.ensureDir(out);
91
- const d = new Date();
92
- const pad = (n: number) => String(n).padStart(2, '0');
93
- const timestamp = `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
94
- const fileName = `ariaease-report-${timestamp}.${format}`;
95
- const filePath = path.join(out, fileName);
96
-
97
- await fs.writeFile(filePath, formatted, 'utf-8');
98
- console.log(chalk.magentaBright(`📁 Report saved to ${filePath}`));
99
- }
100
-
101
- if(['json', 'csv', 'html'].includes(format)) {
102
- await createReport(format);
103
- } else if(format === 'all') {
104
- await Promise.all(['json', 'csv', 'html'].map((format) => createReport(format)));
105
- }
106
-
107
- console.log(chalk.green('\n🎉 All audits completed.'));
108
- })
109
-
110
- program.command('test')
111
- .description('Run core a11y accessibility standard tests on UI components')
112
- .action(() => {
113
- runTest();
114
- })
115
-
116
- program.command('help')
117
- .description('Display help information')
118
- .action(() => {
119
- program.outputHelp();
120
- });
121
-
122
- program.parse(process.argv);
@@ -1,19 +0,0 @@
1
- import { AriaEaseConfig } from "Types";
2
- /**
3
- * Searches for and loads an AriaEase config file
4
- * Checks for config files in this order:
5
- * - ariaease.config.js
6
- * - ariaease.config.mjs
7
- * - ariaease.config.cjs
8
- * - ariaease.config.json
9
- * - ariaease.config.ts
10
- *
11
- * @param cwd - Current working directory to search in
12
- * @returns Object containing the config and any errors
13
- */
14
- export declare function loadConfig(cwd?: string): Promise<{
15
- config: AriaEaseConfig;
16
- configPath: string | null;
17
- errors: string[];
18
- }>;
19
- //# sourceMappingURL=configLoader.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"configLoader.d.ts","sourceRoot":"","sources":["configLoader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AA0GvC;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC;IACrE,MAAM,EAAE,cAAc,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC,CA6CD"}
@@ -1,155 +0,0 @@
1
- import path from "path";
2
- import fs from "fs-extra";
3
- /**
4
- * Validates the structure of an AriaEase config object
5
- * @param config - The config object to validate
6
- * @returns Validation result with errors if any
7
- */
8
- function validateConfig(config) {
9
- const errors = [];
10
- if (!config || typeof config !== 'object') {
11
- errors.push('Config must be an object');
12
- return { valid: false, errors };
13
- }
14
- const cfg = config;
15
- // Validate audit config if present
16
- if (cfg.audit !== undefined) {
17
- if (typeof cfg.audit !== 'object' || cfg.audit === null) {
18
- errors.push('audit must be an object');
19
- }
20
- else {
21
- // Validate urls
22
- if (cfg.audit.urls !== undefined) {
23
- if (!Array.isArray(cfg.audit.urls)) {
24
- errors.push('audit.urls must be an array');
25
- }
26
- else if (cfg.audit.urls.some(url => typeof url !== 'string')) {
27
- errors.push('audit.urls must contain only strings');
28
- }
29
- }
30
- // Validate output format
31
- if (cfg.audit.output !== undefined) {
32
- if (typeof cfg.audit.output !== 'object') {
33
- errors.push('audit.output must be an object');
34
- }
35
- else {
36
- const output = cfg.audit.output;
37
- if (output.format !== undefined) {
38
- if (!['json', 'csv', 'html', 'all'].includes(output.format)) {
39
- errors.push('audit.output.format must be one of: json, csv, html, all');
40
- }
41
- }
42
- if (output.out !== undefined && typeof output.out !== 'string') {
43
- errors.push('audit.output.out must be a string');
44
- }
45
- }
46
- }
47
- }
48
- }
49
- // Validate test config if present
50
- if (cfg.test !== undefined) {
51
- if (typeof cfg.test !== 'object' || cfg.test === null) {
52
- errors.push('test must be an object');
53
- }
54
- else {
55
- if (cfg.test.components !== undefined) {
56
- if (!Array.isArray(cfg.test.components)) {
57
- errors.push('test.components must be an array');
58
- }
59
- else {
60
- cfg.test.components.forEach((comp, idx) => {
61
- if (typeof comp !== 'object' || comp === null) {
62
- errors.push(`test.components[${idx}] must be an object`);
63
- }
64
- else {
65
- if (typeof comp.name !== 'string') {
66
- errors.push(`test.components[${idx}].name must be a string`);
67
- }
68
- if (typeof comp.path !== 'string') {
69
- errors.push(`test.components[${idx}].path must be a string`);
70
- }
71
- }
72
- });
73
- }
74
- }
75
- }
76
- }
77
- return { valid: errors.length === 0, errors };
78
- }
79
- /**
80
- * Attempts to load and parse a config file
81
- * @param filePath - Absolute path to the config file
82
- * @returns The parsed config or null if loading fails
83
- */
84
- async function loadConfigFile(filePath) {
85
- try {
86
- const ext = path.extname(filePath);
87
- if (ext === '.json') {
88
- // Load JSON file
89
- const content = await fs.readFile(filePath, 'utf-8');
90
- return JSON.parse(content);
91
- }
92
- else if (['.js', '.mjs', '.cjs', '.ts'].includes(ext)) {
93
- // Dynamic import for JS/TS modules
94
- const imported = await import(filePath);
95
- // Handle both default export and named exports
96
- return imported.default || imported;
97
- }
98
- return null;
99
- }
100
- catch {
101
- // Return null on any error - caller will handle
102
- return null;
103
- }
104
- }
105
- /**
106
- * Searches for and loads an AriaEase config file
107
- * Checks for config files in this order:
108
- * - ariaease.config.js
109
- * - ariaease.config.mjs
110
- * - ariaease.config.cjs
111
- * - ariaease.config.json
112
- * - ariaease.config.ts
113
- *
114
- * @param cwd - Current working directory to search in
115
- * @returns Object containing the config and any errors
116
- */
117
- export async function loadConfig(cwd = process.cwd()) {
118
- const configNames = [
119
- 'ariaease.config.js',
120
- 'ariaease.config.mjs',
121
- 'ariaease.config.cjs',
122
- 'ariaease.config.json',
123
- 'ariaease.config.ts'
124
- ];
125
- let loadedConfig = null;
126
- let foundPath = null;
127
- const errors = [];
128
- // Try to find and load config
129
- for (const name of configNames) {
130
- const configPath = path.resolve(cwd, name);
131
- if (await fs.pathExists(configPath)) {
132
- foundPath = configPath;
133
- loadedConfig = await loadConfigFile(configPath);
134
- if (loadedConfig === null) {
135
- errors.push(`Found config at ${name} but failed to load it. Check for syntax errors.`);
136
- continue;
137
- }
138
- // Validate the loaded config
139
- const validation = validateConfig(loadedConfig);
140
- if (!validation.valid) {
141
- errors.push(`Config validation failed in ${name}:`);
142
- errors.push(...validation.errors.map(err => ` - ${err}`));
143
- loadedConfig = null;
144
- continue;
145
- }
146
- // Successfully loaded and validated
147
- break;
148
- }
149
- }
150
- return {
151
- config: loadedConfig || {},
152
- configPath: loadedConfig ? foundPath : null,
153
- errors
154
- };
155
- }
@@ -1,170 +0,0 @@
1
- import path from "path";
2
- import fs from "fs-extra";
3
- import { AriaEaseConfig } from "Types";
4
-
5
- /**
6
- * Validates the structure of an AriaEase config object
7
- * @param config - The config object to validate
8
- * @returns Validation result with errors if any
9
- */
10
- function validateConfig(config: unknown): { valid: boolean; errors: string[] } {
11
- const errors: string[] = [];
12
-
13
- if (!config || typeof config !== 'object') {
14
- errors.push('Config must be an object');
15
- return { valid: false, errors };
16
- }
17
-
18
- const cfg = config as Partial<AriaEaseConfig>;
19
-
20
- // Validate audit config if present
21
- if (cfg.audit !== undefined) {
22
- if (typeof cfg.audit !== 'object' || cfg.audit === null) {
23
- errors.push('audit must be an object');
24
- } else {
25
- // Validate urls
26
- if (cfg.audit.urls !== undefined) {
27
- if (!Array.isArray(cfg.audit.urls)) {
28
- errors.push('audit.urls must be an array');
29
- } else if (cfg.audit.urls.some(url => typeof url !== 'string')) {
30
- errors.push('audit.urls must contain only strings');
31
- }
32
- }
33
-
34
- // Validate output format
35
- if (cfg.audit.output !== undefined) {
36
- if (typeof cfg.audit.output !== 'object') {
37
- errors.push('audit.output must be an object');
38
- } else {
39
- const output = cfg.audit.output as { format?: string; out?: string };
40
- if (output.format !== undefined) {
41
- if (!['json', 'csv', 'html', 'all'].includes(output.format)) {
42
- errors.push('audit.output.format must be one of: json, csv, html, all');
43
- }
44
- }
45
- if (output.out !== undefined && typeof output.out !== 'string') {
46
- errors.push('audit.output.out must be a string');
47
- }
48
- }
49
- }
50
- }
51
- }
52
-
53
- // Validate test config if present
54
- if (cfg.test !== undefined) {
55
- if (typeof cfg.test !== 'object' || cfg.test === null) {
56
- errors.push('test must be an object');
57
- } else {
58
- if (cfg.test.components !== undefined) {
59
- if (!Array.isArray(cfg.test.components)) {
60
- errors.push('test.components must be an array');
61
- } else {
62
- cfg.test.components.forEach((comp, idx) => {
63
- if (typeof comp !== 'object' || comp === null) {
64
- errors.push(`test.components[${idx}] must be an object`);
65
- } else {
66
- if (typeof comp.name !== 'string') {
67
- errors.push(`test.components[${idx}].name must be a string`);
68
- }
69
- if (typeof comp.path !== 'string') {
70
- errors.push(`test.components[${idx}].path must be a string`);
71
- }
72
- }
73
- });
74
- }
75
- }
76
- }
77
- }
78
-
79
- return { valid: errors.length === 0, errors };
80
- }
81
-
82
- /**
83
- * Attempts to load and parse a config file
84
- * @param filePath - Absolute path to the config file
85
- * @returns The parsed config or null if loading fails
86
- */
87
- async function loadConfigFile(filePath: string): Promise<AriaEaseConfig | null> {
88
- try {
89
- const ext = path.extname(filePath);
90
-
91
- if (ext === '.json') {
92
- // Load JSON file
93
- const content = await fs.readFile(filePath, 'utf-8');
94
- return JSON.parse(content);
95
- } else if (['.js', '.mjs', '.cjs', '.ts'].includes(ext)) {
96
- // Dynamic import for JS/TS modules
97
- const imported = await import(filePath);
98
- // Handle both default export and named exports
99
- return imported.default || imported;
100
- }
101
-
102
- return null;
103
- } catch {
104
- // Return null on any error - caller will handle
105
- return null;
106
- }
107
- }
108
-
109
- /**
110
- * Searches for and loads an AriaEase config file
111
- * Checks for config files in this order:
112
- * - ariaease.config.js
113
- * - ariaease.config.mjs
114
- * - ariaease.config.cjs
115
- * - ariaease.config.json
116
- * - ariaease.config.ts
117
- *
118
- * @param cwd - Current working directory to search in
119
- * @returns Object containing the config and any errors
120
- */
121
- export async function loadConfig(cwd: string = process.cwd()): Promise<{
122
- config: AriaEaseConfig;
123
- configPath: string | null;
124
- errors: string[];
125
- }> {
126
- const configNames = [
127
- 'ariaease.config.js',
128
- 'ariaease.config.mjs',
129
- 'ariaease.config.cjs',
130
- 'ariaease.config.json',
131
- 'ariaease.config.ts'
132
- ];
133
-
134
- let loadedConfig: AriaEaseConfig | null = null;
135
- let foundPath: string | null = null;
136
- const errors: string[] = [];
137
-
138
- // Try to find and load config
139
- for (const name of configNames) {
140
- const configPath = path.resolve(cwd, name);
141
-
142
- if (await fs.pathExists(configPath)) {
143
- foundPath = configPath;
144
- loadedConfig = await loadConfigFile(configPath);
145
-
146
- if (loadedConfig === null) {
147
- errors.push(`Found config at ${name} but failed to load it. Check for syntax errors.`);
148
- continue;
149
- }
150
-
151
- // Validate the loaded config
152
- const validation = validateConfig(loadedConfig);
153
- if (!validation.valid) {
154
- errors.push(`Config validation failed in ${name}:`);
155
- errors.push(...validation.errors.map(err => ` - ${err}`));
156
- loadedConfig = null;
157
- continue;
158
- }
159
-
160
- // Successfully loaded and validated
161
- break;
162
- }
163
- }
164
-
165
- return {
166
- config: loadedConfig || {},
167
- configPath: loadedConfig ? foundPath : null,
168
- errors
169
- };
170
- }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/test/contract/contractTestRunnerPlaywright.ts","../src/utils/test/contract/contract.json","../src/utils/test/contract/ContractReporter.ts"],"sourcesContent":["import { chromium, Browser, Page } from \"playwright\";\nimport { readFileSync } from \"fs\";\nimport contract from \"./contract.json\";\nimport type { ComponentContract, Contract } from \"Types\";\nimport { ContractReporter } from \"./ContractReporter\";\n\nexport interface ContractTestResult {\n passes: string[];\n failures: string[];\n}\n\nexport async function runContractTestsPlaywright(componentName: string, url: string): Promise<ContractTestResult> {\n const reporter = new ContractReporter(true);\n \n const contractTyped: Contract = contract;\n const contractPath = contractTyped[componentName]?.path;\n\n if (!contractPath) {\n throw new Error(`Contract path not found for component: ${componentName}`);\n }\n\n const resolvedPath = new URL(contractPath, import.meta.url).pathname;\n const contractData = readFileSync(resolvedPath, \"utf-8\");\n const componentContract: ComponentContract = JSON.parse(contractData);\n\n const totalTests = componentContract.static[0].assertions.length + componentContract.dynamic.length;\n reporter.start(componentName, totalTests);\n\n const failures: string[] = [];\n const passes: string[] = [];\n //const skipped: string[] = [];\n let browser: Browser | null = null;\n\n try {\n browser = await chromium.launch({ headless: true });\n const context = await browser.newContext();\n const page: Page = await context.newPage();\n\n await page.goto(url, { waitUntil: \"networkidle\" });\n \n await page.waitForSelector(componentContract.selectors.trigger, { timeout: 5000 });\n\n async function resolveRelativeTarget(selector: string, relative: string) {\n const items = await page.locator(selector).all();\n \n switch (relative) {\n case \"first\":\n return items[0];\n case \"second\":\n return items[1];\n case \"last\":\n return items[items.length - 1];\n case \"next\": {\n const currentIndex = await page.evaluate(([sel]) => {\n const items = Array.from(document.querySelectorAll(sel as string));\n return items.indexOf(document.activeElement as Element);\n }, [selector]);\n const nextIndex = (currentIndex + 1) % items.length;\n return items[nextIndex];\n }\n case \"previous\": {\n const currentIndex = await page.evaluate(([sel]) => {\n const items = Array.from(document.querySelectorAll(sel as string));\n return items.indexOf(document.activeElement as Element);\n }, [selector]);\n const prevIndex = (currentIndex - 1 + items.length) % items.length;\n return items[prevIndex];\n }\n default:\n return null;\n }\n }\n\n // Run static tests\n for (const test of componentContract.static[0]?.assertions || []) {\n if (test.target === \"relative\") continue;\n\n const targetSelector = componentContract.selectors[test.target as keyof typeof componentContract.selectors];\n if (!targetSelector) {\n failures.push(`Selector for target ${test.target} not found.`);\n continue;\n }\n const target = page.locator(targetSelector).first();\n\n const exists = await target.count() > 0;\n if (!exists) {\n failures.push(`Target ${test.target} not found.`);\n continue;\n }\n\n if (!test.expectedValue) {\n const attributes = test.attribute.split(\" | \");\n let hasAny = false;\n for (const attr of attributes) {\n const value = await target.getAttribute(attr.trim());\n if (value !== null) {\n hasAny = true;\n break;\n }\n }\n if (!hasAny) {\n failures.push(test.failureMessage + ` None of the attributes \"${test.attribute}\" are present.`);\n } else {\n passes.push(`At least one of the attributes \"${test.attribute}\" exists on the element.`);\n }\n } else {\n const attributeValue = await target.getAttribute(test.attribute);\n const expectedValues = test.expectedValue.split(\" | \");\n if (!attributeValue || !expectedValues.includes(attributeValue)) {\n failures.push(test.failureMessage + ` Attribute value does not match expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);\n } else {\n passes.push(`Attribute value matches expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);\n }\n }\n }\n\n // Run dynamic tests\n for (const dynamicTest of componentContract.dynamic || []) {\n const { action, assertions } = dynamicTest;\n \n const failuresBeforeTest = failures.length;\n\n // Reset component state before each test for proper isolation\n const containerElement = page.locator(componentContract.selectors.container).first();\n const triggerElement = page.locator(componentContract.selectors.trigger).first();\n const isContainerVisible = await containerElement.isVisible();\n if (isContainerVisible) {\n await triggerElement.click(); // Close the component\n await page.waitForTimeout(50); // Wait for state update\n }\n\n for (const act of action) {\n if (act.type === \"click\") {\n if (act.target === \"document\") {\n await page.mouse.click(10, 10);\n } else {\n const actionSelector = componentContract.selectors[act.target as keyof typeof componentContract.selectors];\n if (!actionSelector) {\n failures.push(`Selector for action target ${act.target} not found.`);\n continue;\n }\n await page.locator(actionSelector).first().click();\n await page.waitForTimeout(200);\n }\n }\n\n if (act.type === \"keypress\" && act.key) {\n const keyMap: Record<string, string> = {\n \"Space\": \"Space\",\n \"Enter\": \"Enter\",\n \"Escape\": \"Escape\",\n \"Arrow Up\": \"ArrowUp\",\n \"Arrow Down\": \"ArrowDown\",\n \"Arrow Left\": \"ArrowLeft\",\n \"Arrow Right\": \"ArrowRight\",\n \"Home\": \"Home\",\n \"End\": \"End\",\n \"Tab\": \"Tab\"\n };\n\n let keyValue = keyMap[act.key] || act.key;\n if (keyValue === \"Space\") {\n keyValue = \" \";\n } else if (keyValue.includes(\" \")) {\n keyValue = keyValue.replace(/ /g, \"\");\n }\n\n if (act.target === \"focusable\" && [\"ArrowUp\", \"ArrowDown\", \"ArrowLeft\", \"ArrowRight\", \"Escape\"].includes(keyValue)) {\n await page.waitForTimeout(100);\n await page.keyboard.press(keyValue);\n await page.waitForTimeout(50);\n } else {\n const keypressSelector = componentContract.selectors[act.target as keyof typeof componentContract.selectors];\n if (!keypressSelector) {\n failures.push(`Selector for keypress target ${act.target} not found.`);\n continue;\n }\n const target = page.locator(keypressSelector).first();\n await target.press(keyValue);\n }\n }\n\n await page.waitForTimeout(100);\n }\n\n // Evaluate assertions after action chain completes\n for (const assertion of assertions) {\n let target;\n\n if (assertion.target === \"relative\") {\n const relativeSelector = componentContract.selectors.relative;\n if (!relativeSelector) {\n failures.push(\"Relative selector is not defined in the contract.\");\n continue;\n }\n if (!assertion.expectedValue) {\n failures.push(\"Expected value for relative target is not defined.\");\n continue;\n }\n target = await resolveRelativeTarget(relativeSelector, assertion.expectedValue);\n } else {\n const assertionSelector = componentContract.selectors[assertion.target as keyof typeof componentContract.selectors];\n if (!assertionSelector) {\n failures.push(`Selector for assertion target ${assertion.target} not found.`);\n continue;\n }\n target = page.locator(assertionSelector).first();\n }\n\n if (!target) {\n failures.push(`Target ${assertion.target} not found.`);\n continue;\n }\n\n // Evaluate assertion\n if (assertion.assertion === \"toBeVisible\") {\n const isVisible = await target.isVisible();\n if (isVisible) {\n passes.push(`${assertion.target} is visible as expected. Test: \"${dynamicTest.description}\".`);\n } else {\n failures.push(`${assertion.failureMessage}`);\n }\n }\n\n if (assertion.assertion === \"notToBeVisible\") {\n const isVisible = await target.isVisible();\n if (!isVisible) {\n passes.push(`${assertion.target} is not visible as expected. Test: \"${dynamicTest.description}\".`);\n } else {\n failures.push(assertion.failureMessage + ` ${assertion.target} is still visible.`);\n }\n }\n\n if (assertion.assertion === \"toHaveAttribute\" && assertion.attribute && assertion.expectedValue) {\n const attributeValue = await target.getAttribute(assertion.attribute);\n if (attributeValue === assertion.expectedValue) {\n passes.push(`${assertion.target} has expected \"${assertion.attribute}\". Test: \"${dynamicTest.description}\".`);\n } else {\n failures.push(assertion.failureMessage + ` ${assertion.target} \"${assertion.attribute}\" should be \"${assertion.expectedValue}\", found \"${attributeValue}\".`);\n }\n }\n\n if (assertion.assertion === \"toHaveFocus\") {\n const hasFocus = await target.evaluate((el) => el === document.activeElement);\n if (hasFocus) {\n passes.push(`${assertion.target} has focus as expected. Test: \"${dynamicTest.description}\".`);\n } else {\n failures.push(`${assertion.failureMessage}`);\n }\n }\n\n if (assertion.assertion === \"toHaveRole\" && assertion.expectedValue) {\n const roleValue = await target.getAttribute(\"role\");\n if (roleValue === assertion.expectedValue) {\n passes.push(`${assertion.target} has role \"${assertion.expectedValue}\". Test: \"${dynamicTest.description}\".`);\n } else {\n failures.push(assertion.failureMessage + ` Expected role \"${assertion.expectedValue}\", found \"${roleValue}\".`);\n }\n }\n }\n \n // Report test result\n const failuresAfterTest = failures.length;\n const testPassed = failuresAfterTest === failuresBeforeTest;\n const failureMessage = testPassed ? undefined : failures[failures.length - 1];\n reporter.reportTest(dynamicTest, testPassed ? 'pass' : 'fail', failureMessage);\n }\n \n // Report static test summary\n const staticPassed = componentContract.static[0].assertions.length;\n const staticFailed = 0;\n reporter.reportStatic(staticPassed, staticFailed);\n \n // Final summary\n reporter.summary(failures);\n\n } catch (error: unknown) {\n if (error instanceof Error) {\n if (error.message.includes(\"Executable doesn't exist\")) {\n console.error(\"\\n❌ Playwright browsers not found!\\n\");\n console.log(\"📦 Run: npx playwright install chromium\\n\");\n failures.push(\"Playwright browser not installed. Run: npx playwright install chromium\");\n } else if (error.message.includes(\"net::ERR_CONNECTION_REFUSED\")) {\n console.error(\"\\n❌ Cannot connect to dev server!\\n\");\n console.log(` Make sure your dev server is running at ${url}\\n`);\n failures.push(`Dev server not running at ${url}`);\n } else {\n console.error(\"❌ Playwright test error:\", error.message);\n failures.push(`Test error: ${error.message}`);\n }\n }\n } finally {\n if (browser) await browser.close();\n }\n\n return { passes, failures };\n}","{\n \"menu\": {\n \"path\": \"./contracts/MenuContract.json\",\n \"component\": \"menu\"\n }\n}","/**\n * Contract Test Reporter - Vitest-style output for accessibility contract tests\n * Provides clear, actionable feedback with proper formatting and context\n */\n\ninterface TestResult {\n description: string;\n status: 'pass' | 'fail' | 'skip';\n failureMessage?: string;\n skipReason?: string;\n}\n\nexport class ContractReporter {\n private startTime: number = 0;\n private componentName: string = '';\n private staticPasses: number = 0;\n private staticFailures: number = 0;\n private dynamicResults: TestResult[] = [];\n private totalTests: number = 0;\n private skipped: number = 0;\n private isPlaywright: boolean = false;\n\n constructor(isPlaywright: boolean = false) {\n this.isPlaywright = isPlaywright;\n }\n\n private log(message: string) {\n process.stderr.write(message + '\\n');\n }\n\n start(componentName: string, totalTests: number) {\n this.startTime = Date.now();\n this.componentName = componentName;\n this.totalTests = totalTests;\n \n const mode = this.isPlaywright ? 'Playwright (Real Browser)' : 'jsdom (Fast)';\n this.log(`\\n${'═'.repeat(60)}`);\n this.log(`🔍 Testing ${componentName} Component - ${mode}`);\n this.log(`${'═'.repeat(60)}\\n`);\n }\n\n reportStatic(passes: number, failures: number) {\n this.staticPasses = passes;\n this.staticFailures = failures;\n \n const icon = failures === 0 ? '✅' : '❌';\n const status = failures === 0 ? 'PASS' : 'FAIL';\n \n this.log(`${icon} Static ARIA Tests: ${status}`);\n this.log(` ${passes}/${passes + failures} required attributes present\\n`);\n }\n\n /**\n * Report individual dynamic test result\n */\n reportTest(test: { description: string; requiresBrowser?: boolean }, status: 'pass' | 'fail' | 'skip', failureMessage?: string) {\n const result: TestResult = {\n description: test.description,\n status,\n failureMessage,\n };\n\n if (status === 'skip' && test.requiresBrowser) {\n result.skipReason = 'Requires real browser (addEventListener events)';\n }\n\n this.dynamicResults.push(result);\n\n const icons = { pass: '✓', fail: '✗', skip: '○' };\n //const colors = { pass: '', fail: '', skip: '' };\n \n this.log(` ${icons[status]} ${test.description}`);\n \n if (status === 'skip' && !this.isPlaywright) {\n this.log(` ↳ Skipped in jsdom (runs in Playwright)`);\n }\n \n if (status === 'fail' && failureMessage) {\n this.log(` ↳ ${failureMessage}`);\n }\n }\n\n /**\n * Report all failures with actionable context\n */\n private reportFailures(failures: string[]) {\n if (failures.length === 0) return;\n\n this.log(`\\n${'─'.repeat(60)}`);\n this.log(`❌ Failures (${failures.length}):\\n`);\n\n failures.forEach((failure, index) => {\n this.log(`${index + 1}. ${failure}`);\n \n if (failure.includes('aria-')) {\n this.log(` 💡 Add the missing ARIA attribute to improve screen reader support`);\n } else if (failure.includes('focus')) {\n this.log(` 💡 Check keyboard event handlers and focus management`);\n } else if (failure.includes('visible')) {\n this.log(` 💡 Verify display/visibility styles and state management`);\n }\n this.log('');\n });\n }\n\n /**\n * Report skipped tests with helpful context\n */\n private reportSkipped() {\n if (this.skipped === 0 || this.isPlaywright) return;\n\n const skippedTests = this.dynamicResults.filter(r => r.status === 'skip');\n \n this.log(`\\n${'─'.repeat(60)}`);\n this.log(`ℹ️ Skipped Tests (${this.skipped}):\\n`);\n this.log(`These tests use native keyboard events via addEventListener,`);\n this.log(`which jsdom cannot simulate. They run successfully in Playwright.\\n`);\n \n skippedTests.forEach((test, index) => {\n this.log(`${index + 1}. ${test.description}`);\n });\n \n this.log(`\\n💡 Run with Playwright for full validation:`);\n this.log(` testUiComponent('${this.componentName}', component, 'http://localhost:5173/')\\n`);\n }\n\n /**\n * Generate final summary with statistics\n */\n summary(failures: string[]) {\n const duration = Date.now() - this.startTime;\n //const totalDynamic = this.dynamicResults.length;\n const dynamicPasses = this.dynamicResults.filter(r => r.status === 'pass').length;\n const dynamicFailures = this.dynamicResults.filter(r => r.status === 'fail').length;\n this.skipped = this.dynamicResults.filter(r => r.status === 'skip').length;\n \n const totalPasses = this.staticPasses + dynamicPasses;\n const totalFailures = this.staticFailures + dynamicFailures;\n const totalRun = totalPasses + totalFailures;\n\n // Report failures first\n if (failures.length > 0) {\n this.reportFailures(failures);\n }\n\n // Report skipped tests\n this.reportSkipped();\n\n // Summary section\n this.log(`\\n${'═'.repeat(60)}`);\n this.log(`📊 Summary\\n`);\n \n if (totalFailures === 0 && this.skipped === 0) {\n this.log(`✅ All ${totalRun} tests passed!`);\n this.log(` ${this.componentName} component meets APG and WCAG guidelines ✓`);\n } else if (totalFailures === 0) {\n this.log(`✅ ${totalPasses}/${totalRun} tests passed`);\n this.log(`○ ${this.skipped} tests skipped (jsdom limitation)`);\n this.log(` ${this.componentName} component works correctly`);\n } else {\n this.log(`❌ ${totalFailures} test${totalFailures > 1 ? 's' : ''} failed`);\n this.log(`✅ ${totalPasses} test${totalPasses > 1 ? 's' : ''} passed`);\n if (this.skipped > 0) {\n this.log(`○ ${this.skipped} test${this.skipped > 1 ? 's' : ''} skipped`);\n }\n }\n \n this.log(`⏱️ Duration: ${duration}ms`);\n this.log(`${'═'.repeat(60)}\\n`);\n\n // Provide next steps\n if (totalFailures > 0) {\n this.log(`🔧 Next Steps:`);\n this.log(` 1. Review the failures above`);\n this.log(` 2. Fix ARIA attributes and keyboard handlers`);\n this.log(` 3. Re-run tests to verify fixes\\n`);\n } else if (!this.isPlaywright && this.skipped > 0) {\n this.log(`✨ Optional: Run Playwright tests for complete validation\\n`);\n }\n\n return {\n passes: totalPasses,\n failures: totalFailures,\n skipped: this.skipped,\n duration,\n };\n }\n\n /**\n * Report an error during test execution\n */\n error(message: string, context?: string) {\n this.log(`\\n❌ Error: ${message}`);\n if (context) {\n this.log(` Context: ${context}`);\n }\n this.log('');\n }\n}"],"mappings":"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","names":["items"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/test/contract/contract.json","../src/utils/test/contract/ContractReporter.ts"],"sourcesContent":["{\n \"menu\": {\n \"path\": \"./contracts/MenuContract.json\",\n \"component\": \"menu\"\n }\n}","/**\n * Contract Test Reporter - Vitest-style output for accessibility contract tests\n * Provides clear, actionable feedback with proper formatting and context\n */\n\ninterface TestResult {\n description: string;\n status: 'pass' | 'fail' | 'skip';\n failureMessage?: string;\n skipReason?: string;\n}\n\nexport class ContractReporter {\n private startTime: number = 0;\n private componentName: string = '';\n private staticPasses: number = 0;\n private staticFailures: number = 0;\n private dynamicResults: TestResult[] = [];\n private totalTests: number = 0;\n private skipped: number = 0;\n private isPlaywright: boolean = false;\n\n constructor(isPlaywright: boolean = false) {\n this.isPlaywright = isPlaywright;\n }\n\n private log(message: string) {\n process.stderr.write(message + '\\n');\n }\n\n start(componentName: string, totalTests: number) {\n this.startTime = Date.now();\n this.componentName = componentName;\n this.totalTests = totalTests;\n \n const mode = this.isPlaywright ? 'Playwright (Real Browser)' : 'jsdom (Fast)';\n this.log(`\\n${'═'.repeat(60)}`);\n this.log(`🔍 Testing ${componentName} Component - ${mode}`);\n this.log(`${'═'.repeat(60)}\\n`);\n }\n\n reportStatic(passes: number, failures: number) {\n this.staticPasses = passes;\n this.staticFailures = failures;\n \n const icon = failures === 0 ? '✅' : '❌';\n const status = failures === 0 ? 'PASS' : 'FAIL';\n \n this.log(`${icon} Static ARIA Tests: ${status}`);\n this.log(` ${passes}/${passes + failures} required attributes present\\n`);\n }\n\n /**\n * Report individual dynamic test result\n */\n reportTest(test: { description: string; requiresBrowser?: boolean }, status: 'pass' | 'fail' | 'skip', failureMessage?: string) {\n const result: TestResult = {\n description: test.description,\n status,\n failureMessage,\n };\n\n if (status === 'skip' && test.requiresBrowser) {\n result.skipReason = 'Requires real browser (addEventListener events)';\n }\n\n this.dynamicResults.push(result);\n\n const icons = { pass: '✓', fail: '✗', skip: '○' };\n //const colors = { pass: '', fail: '', skip: '' };\n \n this.log(` ${icons[status]} ${test.description}`);\n \n if (status === 'skip' && !this.isPlaywright) {\n this.log(` ↳ Skipped in jsdom (runs in Playwright)`);\n }\n \n if (status === 'fail' && failureMessage) {\n this.log(` ↳ ${failureMessage}`);\n }\n }\n\n /**\n * Report all failures with actionable context\n */\n private reportFailures(failures: string[]) {\n if (failures.length === 0) return;\n\n this.log(`\\n${'─'.repeat(60)}`);\n this.log(`❌ Failures (${failures.length}):\\n`);\n\n failures.forEach((failure, index) => {\n this.log(`${index + 1}. ${failure}`);\n \n if (failure.includes('aria-')) {\n this.log(` 💡 Add the missing ARIA attribute to improve screen reader support`);\n } else if (failure.includes('focus')) {\n this.log(` 💡 Check keyboard event handlers and focus management`);\n } else if (failure.includes('visible')) {\n this.log(` 💡 Verify display/visibility styles and state management`);\n }\n this.log('');\n });\n }\n\n /**\n * Report skipped tests with helpful context\n */\n private reportSkipped() {\n if (this.skipped === 0 || this.isPlaywright) return;\n\n const skippedTests = this.dynamicResults.filter(r => r.status === 'skip');\n \n this.log(`\\n${'─'.repeat(60)}`);\n this.log(`ℹ️ Skipped Tests (${this.skipped}):\\n`);\n this.log(`These tests use native keyboard events via addEventListener,`);\n this.log(`which jsdom cannot simulate. They run successfully in Playwright.\\n`);\n \n skippedTests.forEach((test, index) => {\n this.log(`${index + 1}. ${test.description}`);\n });\n \n this.log(`\\n💡 Run with Playwright for full validation:`);\n this.log(` testUiComponent('${this.componentName}', component, 'http://localhost:5173/')\\n`);\n }\n\n /**\n * Generate final summary with statistics\n */\n summary(failures: string[]) {\n const duration = Date.now() - this.startTime;\n //const totalDynamic = this.dynamicResults.length;\n const dynamicPasses = this.dynamicResults.filter(r => r.status === 'pass').length;\n const dynamicFailures = this.dynamicResults.filter(r => r.status === 'fail').length;\n this.skipped = this.dynamicResults.filter(r => r.status === 'skip').length;\n \n const totalPasses = this.staticPasses + dynamicPasses;\n const totalFailures = this.staticFailures + dynamicFailures;\n const totalRun = totalPasses + totalFailures;\n\n // Report failures first\n if (failures.length > 0) {\n this.reportFailures(failures);\n }\n\n // Report skipped tests\n this.reportSkipped();\n\n // Summary section\n this.log(`\\n${'═'.repeat(60)}`);\n this.log(`📊 Summary\\n`);\n \n if (totalFailures === 0 && this.skipped === 0) {\n this.log(`✅ All ${totalRun} tests passed!`);\n this.log(` ${this.componentName} component meets APG and WCAG guidelines ✓`);\n } else if (totalFailures === 0) {\n this.log(`✅ ${totalPasses}/${totalRun} tests passed`);\n this.log(`○ ${this.skipped} tests skipped (jsdom limitation)`);\n this.log(` ${this.componentName} component works correctly`);\n } else {\n this.log(`❌ ${totalFailures} test${totalFailures > 1 ? 's' : ''} failed`);\n this.log(`✅ ${totalPasses} test${totalPasses > 1 ? 's' : ''} passed`);\n if (this.skipped > 0) {\n this.log(`○ ${this.skipped} test${this.skipped > 1 ? 's' : ''} skipped`);\n }\n }\n \n this.log(`⏱️ Duration: ${duration}ms`);\n this.log(`${'═'.repeat(60)}\\n`);\n\n // Provide next steps\n if (totalFailures > 0) {\n this.log(`🔧 Next Steps:`);\n this.log(` 1. Review the failures above`);\n this.log(` 2. Fix ARIA attributes and keyboard handlers`);\n this.log(` 3. Re-run tests to verify fixes\\n`);\n } else if (!this.isPlaywright && this.skipped > 0) {\n this.log(`✨ Optional: Run Playwright tests for complete validation\\n`);\n }\n\n return {\n passes: totalPasses,\n failures: totalFailures,\n skipped: this.skipped,\n duration,\n };\n }\n\n /**\n * Report an error during test execution\n */\n error(message: string, context?: string) {\n this.log(`\\n❌ Error: ${message}`);\n if (context) {\n this.log(` Context: ${context}`);\n }\n this.log('');\n }\n}"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/test/contract/contractTestRunnerPlaywright.ts"],"sourcesContent":["import { chromium, Browser, Page } from \"playwright\";\nimport { readFileSync } from \"fs\";\nimport contract from \"./contract.json\";\nimport type { ComponentContract, Contract } from \"Types\";\nimport { ContractReporter } from \"./ContractReporter\";\n\nexport interface ContractTestResult {\n passes: string[];\n failures: string[];\n}\n\nexport async function runContractTestsPlaywright(componentName: string, url: string): Promise<ContractTestResult> {\n const reporter = new ContractReporter(true);\n \n const contractTyped: Contract = contract;\n const contractPath = contractTyped[componentName]?.path;\n\n if (!contractPath) {\n throw new Error(`Contract path not found for component: ${componentName}`);\n }\n\n const resolvedPath = new URL(contractPath, import.meta.url).pathname;\n const contractData = readFileSync(resolvedPath, \"utf-8\");\n const componentContract: ComponentContract = JSON.parse(contractData);\n\n const totalTests = componentContract.static[0].assertions.length + componentContract.dynamic.length;\n reporter.start(componentName, totalTests);\n\n const failures: string[] = [];\n const passes: string[] = [];\n //const skipped: string[] = [];\n let browser: Browser | null = null;\n\n try {\n browser = await chromium.launch({ headless: true });\n const context = await browser.newContext();\n const page: Page = await context.newPage();\n\n await page.goto(url, { waitUntil: \"networkidle\" });\n \n await page.waitForSelector(componentContract.selectors.trigger, { timeout: 5000 });\n\n async function resolveRelativeTarget(selector: string, relative: string) {\n const items = await page.locator(selector).all();\n \n switch (relative) {\n case \"first\":\n return items[0];\n case \"second\":\n return items[1];\n case \"last\":\n return items[items.length - 1];\n case \"next\": {\n const currentIndex = await page.evaluate(([sel]) => {\n const items = Array.from(document.querySelectorAll(sel as string));\n return items.indexOf(document.activeElement as Element);\n }, [selector]);\n const nextIndex = (currentIndex + 1) % items.length;\n return items[nextIndex];\n }\n case \"previous\": {\n const currentIndex = await page.evaluate(([sel]) => {\n const items = Array.from(document.querySelectorAll(sel as string));\n return items.indexOf(document.activeElement as Element);\n }, [selector]);\n const prevIndex = (currentIndex - 1 + items.length) % items.length;\n return items[prevIndex];\n }\n default:\n return null;\n }\n }\n\n // Run static tests\n for (const test of componentContract.static[0]?.assertions || []) {\n if (test.target === \"relative\") continue;\n\n const targetSelector = componentContract.selectors[test.target as keyof typeof componentContract.selectors];\n if (!targetSelector) {\n failures.push(`Selector for target ${test.target} not found.`);\n continue;\n }\n const target = page.locator(targetSelector).first();\n\n const exists = await target.count() > 0;\n if (!exists) {\n failures.push(`Target ${test.target} not found.`);\n continue;\n }\n\n if (!test.expectedValue) {\n const attributes = test.attribute.split(\" | \");\n let hasAny = false;\n for (const attr of attributes) {\n const value = await target.getAttribute(attr.trim());\n if (value !== null) {\n hasAny = true;\n break;\n }\n }\n if (!hasAny) {\n failures.push(test.failureMessage + ` None of the attributes \"${test.attribute}\" are present.`);\n } else {\n passes.push(`At least one of the attributes \"${test.attribute}\" exists on the element.`);\n }\n } else {\n const attributeValue = await target.getAttribute(test.attribute);\n const expectedValues = test.expectedValue.split(\" | \");\n if (!attributeValue || !expectedValues.includes(attributeValue)) {\n failures.push(test.failureMessage + ` Attribute value does not match expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);\n } else {\n passes.push(`Attribute value matches expected value. Expected: ${test.expectedValue}, Found: ${attributeValue}`);\n }\n }\n }\n\n // Run dynamic tests\n for (const dynamicTest of componentContract.dynamic || []) {\n const { action, assertions } = dynamicTest;\n \n const failuresBeforeTest = failures.length;\n\n // Reset component state before each test for proper isolation\n const containerElement = page.locator(componentContract.selectors.container).first();\n const triggerElement = page.locator(componentContract.selectors.trigger).first();\n const isContainerVisible = await containerElement.isVisible();\n if (isContainerVisible) {\n await triggerElement.click(); // Close the component\n await page.waitForTimeout(50); // Wait for state update\n }\n\n for (const act of action) {\n if (act.type === \"click\") {\n if (act.target === \"document\") {\n await page.mouse.click(10, 10);\n } else {\n const actionSelector = componentContract.selectors[act.target as keyof typeof componentContract.selectors];\n if (!actionSelector) {\n failures.push(`Selector for action target ${act.target} not found.`);\n continue;\n }\n await page.locator(actionSelector).first().click();\n await page.waitForTimeout(200);\n }\n }\n\n if (act.type === \"keypress\" && act.key) {\n const keyMap: Record<string, string> = {\n \"Space\": \"Space\",\n \"Enter\": \"Enter\",\n \"Escape\": \"Escape\",\n \"Arrow Up\": \"ArrowUp\",\n \"Arrow Down\": \"ArrowDown\",\n \"Arrow Left\": \"ArrowLeft\",\n \"Arrow Right\": \"ArrowRight\",\n \"Home\": \"Home\",\n \"End\": \"End\",\n \"Tab\": \"Tab\"\n };\n\n let keyValue = keyMap[act.key] || act.key;\n if (keyValue === \"Space\") {\n keyValue = \" \";\n } else if (keyValue.includes(\" \")) {\n keyValue = keyValue.replace(/ /g, \"\");\n }\n\n if (act.target === \"focusable\" && [\"ArrowUp\", \"ArrowDown\", \"ArrowLeft\", \"ArrowRight\", \"Escape\"].includes(keyValue)) {\n await page.waitForTimeout(100);\n await page.keyboard.press(keyValue);\n await page.waitForTimeout(50);\n } else {\n const keypressSelector = componentContract.selectors[act.target as keyof typeof componentContract.selectors];\n if (!keypressSelector) {\n failures.push(`Selector for keypress target ${act.target} not found.`);\n continue;\n }\n const target = page.locator(keypressSelector).first();\n await target.press(keyValue);\n }\n }\n\n await page.waitForTimeout(100);\n }\n\n // Evaluate assertions after action chain completes\n for (const assertion of assertions) {\n let target;\n\n if (assertion.target === \"relative\") {\n const relativeSelector = componentContract.selectors.relative;\n if (!relativeSelector) {\n failures.push(\"Relative selector is not defined in the contract.\");\n continue;\n }\n if (!assertion.expectedValue) {\n failures.push(\"Expected value for relative target is not defined.\");\n continue;\n }\n target = await resolveRelativeTarget(relativeSelector, assertion.expectedValue);\n } else {\n const assertionSelector = componentContract.selectors[assertion.target as keyof typeof componentContract.selectors];\n if (!assertionSelector) {\n failures.push(`Selector for assertion target ${assertion.target} not found.`);\n continue;\n }\n target = page.locator(assertionSelector).first();\n }\n\n if (!target) {\n failures.push(`Target ${assertion.target} not found.`);\n continue;\n }\n\n // Evaluate assertion\n if (assertion.assertion === \"toBeVisible\") {\n const isVisible = await target.isVisible();\n if (isVisible) {\n passes.push(`${assertion.target} is visible as expected. Test: \"${dynamicTest.description}\".`);\n } else {\n failures.push(`${assertion.failureMessage}`);\n }\n }\n\n if (assertion.assertion === \"notToBeVisible\") {\n const isVisible = await target.isVisible();\n if (!isVisible) {\n passes.push(`${assertion.target} is not visible as expected. Test: \"${dynamicTest.description}\".`);\n } else {\n failures.push(assertion.failureMessage + ` ${assertion.target} is still visible.`);\n }\n }\n\n if (assertion.assertion === \"toHaveAttribute\" && assertion.attribute && assertion.expectedValue) {\n const attributeValue = await target.getAttribute(assertion.attribute);\n if (attributeValue === assertion.expectedValue) {\n passes.push(`${assertion.target} has expected \"${assertion.attribute}\". Test: \"${dynamicTest.description}\".`);\n } else {\n failures.push(assertion.failureMessage + ` ${assertion.target} \"${assertion.attribute}\" should be \"${assertion.expectedValue}\", found \"${attributeValue}\".`);\n }\n }\n\n if (assertion.assertion === \"toHaveFocus\") {\n const hasFocus = await target.evaluate((el) => el === document.activeElement);\n if (hasFocus) {\n passes.push(`${assertion.target} has focus as expected. Test: \"${dynamicTest.description}\".`);\n } else {\n failures.push(`${assertion.failureMessage}`);\n }\n }\n\n if (assertion.assertion === \"toHaveRole\" && assertion.expectedValue) {\n const roleValue = await target.getAttribute(\"role\");\n if (roleValue === assertion.expectedValue) {\n passes.push(`${assertion.target} has role \"${assertion.expectedValue}\". Test: \"${dynamicTest.description}\".`);\n } else {\n failures.push(assertion.failureMessage + ` Expected role \"${assertion.expectedValue}\", found \"${roleValue}\".`);\n }\n }\n }\n \n // Report test result\n const failuresAfterTest = failures.length;\n const testPassed = failuresAfterTest === failuresBeforeTest;\n const failureMessage = testPassed ? undefined : failures[failures.length - 1];\n reporter.reportTest(dynamicTest, testPassed ? 'pass' : 'fail', failureMessage);\n }\n \n // Report static test summary\n const staticPassed = componentContract.static[0].assertions.length;\n const staticFailed = 0;\n reporter.reportStatic(staticPassed, staticFailed);\n \n // Final summary\n reporter.summary(failures);\n\n } catch (error: unknown) {\n if (error instanceof Error) {\n if (error.message.includes(\"Executable doesn't exist\")) {\n console.error(\"\\n❌ Playwright browsers not found!\\n\");\n console.log(\"📦 Run: npx playwright install chromium\\n\");\n failures.push(\"Playwright browser not installed. Run: npx playwright install chromium\");\n } else if (error.message.includes(\"net::ERR_CONNECTION_REFUSED\")) {\n console.error(\"\\n❌ Cannot connect to dev server!\\n\");\n console.log(` Make sure your dev server is running at ${url}\\n`);\n failures.push(`Dev server not running at ${url}`);\n } else {\n console.error(\"❌ Playwright test error:\", error.message);\n failures.push(`Test error: ${error.message}`);\n }\n }\n } finally {\n if (browser) await browser.close();\n }\n\n return { passes, failures };\n}"],"mappings":"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","names":["items"]}