accessibility-server-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +762 -0
- package/config/wcag-rules.json +252 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +437 -0
- package/dist/index.js.map +1 -0
- package/dist/test-manual.d.ts +6 -0
- package/dist/test-manual.d.ts.map +1 -0
- package/dist/test-manual.js +66 -0
- package/dist/test-manual.js.map +1 -0
- package/dist/tools/accessibility-tester.d.ts +56 -0
- package/dist/tools/accessibility-tester.d.ts.map +1 -0
- package/dist/tools/accessibility-tester.js +317 -0
- package/dist/tools/accessibility-tester.js.map +1 -0
- package/dist/tools/color-contrast.d.ts +49 -0
- package/dist/tools/color-contrast.d.ts.map +1 -0
- package/dist/tools/color-contrast.js +237 -0
- package/dist/tools/color-contrast.js.map +1 -0
- package/dist/tools/wcag-validator.d.ts +43 -0
- package/dist/tools/wcag-validator.d.ts.map +1 -0
- package/dist/tools/wcag-validator.js +249 -0
- package/dist/tools/wcag-validator.js.map +1 -0
- package/dist/tools/website-accessibility-tester.d.ts +103 -0
- package/dist/tools/website-accessibility-tester.d.ts.map +1 -0
- package/dist/tools/website-accessibility-tester.js +228 -0
- package/dist/tools/website-accessibility-tester.js.map +1 -0
- package/dist/types/accessibility.d.ts +172 -0
- package/dist/types/accessibility.d.ts.map +1 -0
- package/dist/types/accessibility.js +5 -0
- package/dist/types/accessibility.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/mcp.d.ts +70 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +5 -0
- package/dist/types/mcp.js.map +1 -0
- package/dist/utils/browser-manager.d.ts +83 -0
- package/dist/utils/browser-manager.d.ts.map +1 -0
- package/dist/utils/browser-manager.js +292 -0
- package/dist/utils/browser-manager.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +107 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/report-generator.d.ts +31 -0
- package/dist/utils/report-generator.d.ts.map +1 -0
- package/dist/utils/report-generator.js +252 -0
- package/dist/utils/report-generator.js.map +1 -0
- package/dist/utils/website-crawler.d.ts +66 -0
- package/dist/utils/website-crawler.d.ts.map +1 -0
- package/dist/utils/website-crawler.js +306 -0
- package/dist/utils/website-crawler.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { WCAGRule, AccessibilityCategory, WCAGLevel, WCAGVersion } from '../types/index.js';
|
|
2
|
+
import type { GetWCAGRulesInput, ToolResponse } from '../types/mcp.js';
|
|
3
|
+
/**
|
|
4
|
+
* WCAG rules validator and information provider
|
|
5
|
+
*/
|
|
6
|
+
export declare class WCAGValidator {
|
|
7
|
+
private readonly logger;
|
|
8
|
+
private wcagConfig;
|
|
9
|
+
constructor();
|
|
10
|
+
/**
|
|
11
|
+
* Get WCAG rules based on filters
|
|
12
|
+
*/
|
|
13
|
+
getRules(input: GetWCAGRulesInput): Promise<ToolResponse<WCAGRule[]>>;
|
|
14
|
+
/**
|
|
15
|
+
* Load WCAG configuration from file
|
|
16
|
+
*/
|
|
17
|
+
private loadWCAGConfig;
|
|
18
|
+
/**
|
|
19
|
+
* Get all available WCAG rules
|
|
20
|
+
*/
|
|
21
|
+
private getAllRules;
|
|
22
|
+
/**
|
|
23
|
+
* Apply filters to rules
|
|
24
|
+
*/
|
|
25
|
+
private applyFilters;
|
|
26
|
+
/**
|
|
27
|
+
* Search rules by title and description
|
|
28
|
+
*/
|
|
29
|
+
private searchRules;
|
|
30
|
+
/**
|
|
31
|
+
* Determine test type based on rule characteristics
|
|
32
|
+
*/
|
|
33
|
+
private determineTestType;
|
|
34
|
+
/**
|
|
35
|
+
* Get rules for specific WCAG level and version
|
|
36
|
+
*/
|
|
37
|
+
getRulesForLevel(wcagLevel: WCAGLevel, wcagVersion: WCAGVersion): Promise<string[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Get rules for specific category
|
|
40
|
+
*/
|
|
41
|
+
getRulesForCategory(category: AccessibilityCategory): Promise<string[]>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=wcag-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wcag-validator.d.ts","sourceRoot":"","sources":["../../src/tools/wcag-validator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC5F,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAuBvE;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,UAAU,CAA2B;;IAM7C;;OAEG;IACG,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC;IA8D3E;;OAEG;YACW,cAAc;IAa5B;;OAEG;IACH,OAAO,CAAC,WAAW;IA2EnB;;OAEG;IACH,OAAO,CAAC,YAAY;IA6BpB;;OAEG;IACH,OAAO,CAAC,WAAW;IAYnB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;OAEG;IACG,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA8BzF;;OAEG;IACG,mBAAmB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAW9E"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { Logger } from '../utils/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* WCAG rules validator and information provider
|
|
6
|
+
*/
|
|
7
|
+
export class WCAGValidator {
|
|
8
|
+
logger;
|
|
9
|
+
wcagConfig = null;
|
|
10
|
+
constructor() {
|
|
11
|
+
this.logger = new Logger().child({ component: 'WCAGValidator' });
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get WCAG rules based on filters
|
|
15
|
+
*/
|
|
16
|
+
async getRules(input) {
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
try {
|
|
19
|
+
this.logger.info('Getting WCAG rules', { filters: input });
|
|
20
|
+
// Load WCAG configuration if not already loaded
|
|
21
|
+
if (!this.wcagConfig) {
|
|
22
|
+
await this.loadWCAGConfig();
|
|
23
|
+
}
|
|
24
|
+
if (!this.wcagConfig) {
|
|
25
|
+
throw new Error('Failed to load WCAG configuration');
|
|
26
|
+
}
|
|
27
|
+
// Get all available rules
|
|
28
|
+
const allRules = this.getAllRules();
|
|
29
|
+
// Apply filters
|
|
30
|
+
let filteredRules = this.applyFilters(allRules, input);
|
|
31
|
+
// Apply search if provided
|
|
32
|
+
if (input.search) {
|
|
33
|
+
filteredRules = this.searchRules(filteredRules, input.search);
|
|
34
|
+
}
|
|
35
|
+
// Apply limit
|
|
36
|
+
if (input.limit && filteredRules.length > input.limit) {
|
|
37
|
+
filteredRules = filteredRules.slice(0, input.limit);
|
|
38
|
+
}
|
|
39
|
+
this.logger.info('WCAG rules retrieved', {
|
|
40
|
+
totalRules: allRules.length,
|
|
41
|
+
filteredRules: filteredRules.length
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
success: true,
|
|
45
|
+
data: filteredRules,
|
|
46
|
+
processingTime: Date.now() - startTime,
|
|
47
|
+
timestamp: new Date().toISOString()
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
this.logger.error('Error getting WCAG rules', error instanceof Error ? error : new Error(String(error)));
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
error: {
|
|
55
|
+
type: 'internal',
|
|
56
|
+
message: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
57
|
+
details: error instanceof Error ? {
|
|
58
|
+
name: error.name,
|
|
59
|
+
stack: error.stack
|
|
60
|
+
} : undefined
|
|
61
|
+
},
|
|
62
|
+
processingTime: Date.now() - startTime,
|
|
63
|
+
timestamp: new Date().toISOString()
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Load WCAG configuration from file
|
|
69
|
+
*/
|
|
70
|
+
async loadWCAGConfig() {
|
|
71
|
+
try {
|
|
72
|
+
const configPath = path.join(process.cwd(), 'config', 'wcag-rules.json');
|
|
73
|
+
const configData = await fs.readFile(configPath, 'utf8');
|
|
74
|
+
this.wcagConfig = JSON.parse(configData);
|
|
75
|
+
this.logger.debug('WCAG configuration loaded successfully');
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
this.logger.error('Failed to load WCAG configuration', error instanceof Error ? error : new Error(String(error)));
|
|
79
|
+
throw new Error('Could not load WCAG rules configuration');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get all available WCAG rules
|
|
84
|
+
*/
|
|
85
|
+
getAllRules() {
|
|
86
|
+
if (!this.wcagConfig) {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
const rules = [];
|
|
90
|
+
const { wcagRules, categories, ruleDescriptions } = this.wcagConfig;
|
|
91
|
+
// Collect all unique rule IDs
|
|
92
|
+
const allRuleIds = new Set();
|
|
93
|
+
Object.values(wcagRules).forEach(versionRules => {
|
|
94
|
+
Object.values(versionRules.level).forEach(levelRules => {
|
|
95
|
+
levelRules.forEach(ruleId => allRuleIds.add(ruleId));
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
// Create WCAGRule objects
|
|
99
|
+
allRuleIds.forEach(ruleId => {
|
|
100
|
+
const description = ruleDescriptions[ruleId];
|
|
101
|
+
if (!description) {
|
|
102
|
+
this.logger.warn(`No description found for rule: ${ruleId}`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
// Determine which versions and levels this rule applies to
|
|
106
|
+
const versions = [];
|
|
107
|
+
let level = 'A';
|
|
108
|
+
Object.entries(wcagRules).forEach(([version, versionData]) => {
|
|
109
|
+
Object.entries(versionData.level).forEach(([lvl, rules]) => {
|
|
110
|
+
if (rules.includes(ruleId)) {
|
|
111
|
+
if (!versions.includes(version)) {
|
|
112
|
+
versions.push(version);
|
|
113
|
+
}
|
|
114
|
+
// Use the highest level found
|
|
115
|
+
if (lvl === 'AAA' || (lvl === 'AA' && level === 'A')) {
|
|
116
|
+
level = lvl;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
// Determine categories
|
|
122
|
+
const ruleCategories = [];
|
|
123
|
+
Object.entries(categories).forEach(([category, categoryRules]) => {
|
|
124
|
+
if (categoryRules.includes(ruleId)) {
|
|
125
|
+
ruleCategories.push(category);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
// Generate tags
|
|
129
|
+
const tags = [
|
|
130
|
+
...ruleCategories,
|
|
131
|
+
...versions.map(v => `wcag${v.replace('.', '')}`),
|
|
132
|
+
`level-${level.toLowerCase()}`
|
|
133
|
+
];
|
|
134
|
+
rules.push({
|
|
135
|
+
id: ruleId,
|
|
136
|
+
title: description.title,
|
|
137
|
+
description: description.description,
|
|
138
|
+
level,
|
|
139
|
+
versions,
|
|
140
|
+
categories: ruleCategories,
|
|
141
|
+
tags,
|
|
142
|
+
wcagUrl: description.helpUrl,
|
|
143
|
+
testType: this.determineTestType(ruleId),
|
|
144
|
+
successCriteria: description.successCriteria
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
return rules.sort((a, b) => a.id.localeCompare(b.id));
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Apply filters to rules
|
|
151
|
+
*/
|
|
152
|
+
applyFilters(rules, filters) {
|
|
153
|
+
let filtered = [...rules];
|
|
154
|
+
// Filter by WCAG level
|
|
155
|
+
if (filters.wcagLevel) {
|
|
156
|
+
filtered = filtered.filter(rule => {
|
|
157
|
+
switch (filters.wcagLevel) {
|
|
158
|
+
case 'A':
|
|
159
|
+
return rule.level === 'A';
|
|
160
|
+
case 'AA':
|
|
161
|
+
return ['A', 'AA'].includes(rule.level);
|
|
162
|
+
case 'AAA':
|
|
163
|
+
return ['A', 'AA', 'AAA'].includes(rule.level);
|
|
164
|
+
default:
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// Filter by category
|
|
170
|
+
if (filters.category) {
|
|
171
|
+
filtered = filtered.filter(rule => rule.categories.some(cat => cat.toLowerCase().includes(filters.category.toLowerCase())));
|
|
172
|
+
}
|
|
173
|
+
return filtered;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Search rules by title and description
|
|
177
|
+
*/
|
|
178
|
+
searchRules(rules, searchTerm) {
|
|
179
|
+
const lowercaseSearch = searchTerm.toLowerCase();
|
|
180
|
+
return rules.filter(rule => rule.title.toLowerCase().includes(lowercaseSearch) ||
|
|
181
|
+
rule.description.toLowerCase().includes(lowercaseSearch) ||
|
|
182
|
+
rule.id.toLowerCase().includes(lowercaseSearch) ||
|
|
183
|
+
rule.categories.some(cat => cat.toLowerCase().includes(lowercaseSearch)) ||
|
|
184
|
+
rule.tags.some(tag => tag.toLowerCase().includes(lowercaseSearch)));
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Determine test type based on rule characteristics
|
|
188
|
+
*/
|
|
189
|
+
determineTestType(ruleId) {
|
|
190
|
+
// Rules that are typically automated
|
|
191
|
+
const automatedRules = [
|
|
192
|
+
'color-contrast', 'image-alt', 'label', 'html-has-lang',
|
|
193
|
+
'aria-allowed-attr', 'aria-required-attr', 'aria-valid-attr-value',
|
|
194
|
+
'button-name', 'link-name', 'heading-order'
|
|
195
|
+
];
|
|
196
|
+
// Rules that require manual testing
|
|
197
|
+
const manualRules = [
|
|
198
|
+
'focus-order-semantics', 'page-has-heading-one', 'region',
|
|
199
|
+
'target-size', 'orientation-lock'
|
|
200
|
+
];
|
|
201
|
+
if (automatedRules.some(rule => ruleId.includes(rule))) {
|
|
202
|
+
return 'automated';
|
|
203
|
+
}
|
|
204
|
+
if (manualRules.some(rule => ruleId.includes(rule))) {
|
|
205
|
+
return 'manual';
|
|
206
|
+
}
|
|
207
|
+
return 'semi-automated';
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get rules for specific WCAG level and version
|
|
211
|
+
*/
|
|
212
|
+
async getRulesForLevel(wcagLevel, wcagVersion) {
|
|
213
|
+
if (!this.wcagConfig) {
|
|
214
|
+
await this.loadWCAGConfig();
|
|
215
|
+
}
|
|
216
|
+
if (!this.wcagConfig) {
|
|
217
|
+
return [];
|
|
218
|
+
}
|
|
219
|
+
const versionRules = this.wcagConfig.wcagRules[wcagVersion];
|
|
220
|
+
if (!versionRules) {
|
|
221
|
+
return [];
|
|
222
|
+
}
|
|
223
|
+
const rules = [];
|
|
224
|
+
// Add rules for requested level and below
|
|
225
|
+
if (wcagLevel === 'A' || wcagLevel === 'AA' || wcagLevel === 'AAA') {
|
|
226
|
+
rules.push(...(versionRules.level.A || []));
|
|
227
|
+
}
|
|
228
|
+
if (wcagLevel === 'AA' || wcagLevel === 'AAA') {
|
|
229
|
+
rules.push(...(versionRules.level.AA || []));
|
|
230
|
+
}
|
|
231
|
+
if (wcagLevel === 'AAA') {
|
|
232
|
+
rules.push(...(versionRules.level.AAA || []));
|
|
233
|
+
}
|
|
234
|
+
return [...new Set(rules)]; // Remove duplicates
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Get rules for specific category
|
|
238
|
+
*/
|
|
239
|
+
async getRulesForCategory(category) {
|
|
240
|
+
if (!this.wcagConfig) {
|
|
241
|
+
await this.loadWCAGConfig();
|
|
242
|
+
}
|
|
243
|
+
if (!this.wcagConfig) {
|
|
244
|
+
return [];
|
|
245
|
+
}
|
|
246
|
+
return this.wcagConfig.categories[category] || [];
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=wcag-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wcag-validator.js","sourceRoot":"","sources":["../../src/tools/wcag-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAyB3C;;GAEG;AACH,MAAM,OAAO,aAAa;IACP,MAAM,CAAS;IACxB,UAAU,GAAsB,IAAI,CAAC;IAE7C;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC;IACnE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CAAC,KAAwB;QACrC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAE3D,gDAAgD;YAChD,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;gBACrB,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;YAC9B,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvD,CAAC;YAED,0BAA0B;YAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAEpC,gBAAgB;YAChB,IAAI,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAEvD,2BAA2B;YAC3B,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACjB,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YAChE,CAAC;YAED,cAAc;YACd,IAAI,KAAK,CAAC,KAAK,IAAI,aAAa,CAAC,MAAM,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;gBACtD,aAAa,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YACtD,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE;gBACvC,UAAU,EAAE,QAAQ,CAAC,MAAM;gBAC3B,aAAa,EAAE,aAAa,CAAC,MAAM;aACpC,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,aAAa;gBACnB,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;gBACtC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;QAEJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAEzG,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE;oBACL,IAAI,EAAE,UAAU;oBAChB,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB;oBAC1E,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC;wBAChC,IAAI,EAAE,KAAK,CAAC,IAAI;wBAChB,KAAK,EAAE,KAAK,CAAC,KAAK;qBACnB,CAAC,CAAC,CAAC,SAAS;iBACd;gBACD,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;gBACtC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,cAAc;QAC1B,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC;YACzE,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YACzD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAe,CAAC;YAEvD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAClH,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED;;OAEG;IACK,WAAW;QACjB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAe,EAAE,CAAC;QAC7B,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;QAEpE,8BAA8B;QAC9B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;QAErC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;YAC9C,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;gBACrD,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;YACvD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,0BAA0B;QAC1B,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;YAC1B,MAAM,WAAW,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC7C,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kCAAkC,MAAM,EAAE,CAAC,CAAC;gBAC7D,OAAO;YACT,CAAC;YAED,2DAA2D;YAC3D,MAAM,QAAQ,GAAkB,EAAE,CAAC;YACnC,IAAI,KAAK,GAAc,GAAG,CAAC;YAE3B,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,EAAE;gBAC3D,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;oBACzD,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC3B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAsB,CAAC,EAAE,CAAC;4BAC/C,QAAQ,CAAC,IAAI,CAAC,OAAsB,CAAC,CAAC;wBACxC,CAAC;wBACD,8BAA8B;wBAC9B,IAAI,GAAG,KAAK,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,GAAG,CAAC,EAAE,CAAC;4BACrD,KAAK,GAAG,GAAgB,CAAC;wBAC3B,CAAC;oBACH,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,uBAAuB;YACvB,MAAM,cAAc,GAA4B,EAAE,CAAC;YACnD,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE;gBAC/D,IAAI,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;oBACnC,cAAc,CAAC,IAAI,CAAC,QAAiC,CAAC,CAAC;gBACzD,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,gBAAgB;YAChB,MAAM,IAAI,GAAG;gBACX,GAAG,cAAc;gBACjB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;gBACjD,SAAS,KAAK,CAAC,WAAW,EAAE,EAAE;aAC/B,CAAC;YAEF,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,MAAM;gBACV,KAAK,EAAE,WAAW,CAAC,KAAK;gBACxB,WAAW,EAAE,WAAW,CAAC,WAAW;gBACpC,KAAK;gBACL,QAAQ;gBACR,UAAU,EAAE,cAAc;gBAC1B,IAAI;gBACJ,OAAO,EAAE,WAAW,CAAC,OAAO;gBAC5B,QAAQ,EAAE,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC;gBACxC,eAAe,EAAE,WAAW,CAAC,eAAe;aAC7C,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;IAED;;OAEG;IACK,YAAY,CAAC,KAAiB,EAAE,OAA0B;QAChE,IAAI,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;QAE1B,uBAAuB;QACvB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;gBAChC,QAAQ,OAAO,CAAC,SAAS,EAAE,CAAC;oBAC1B,KAAK,GAAG;wBACN,OAAO,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC;oBAC5B,KAAK,IAAI;wBACP,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAC1C,KAAK,KAAK;wBACR,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACjD;wBACE,OAAO,IAAI,CAAC;gBAChB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAED,qBAAqB;QACrB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CACzF,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,KAAiB,EAAE,UAAkB;QACvD,MAAM,eAAe,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;QAEjD,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CACzB,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;YAClD,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;YACxD,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;YAC/C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;YACxE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CACnE,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,iBAAiB,CAAC,MAAc;QACtC,qCAAqC;QACrC,MAAM,cAAc,GAAG;YACrB,gBAAgB,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe;YACvD,mBAAmB,EAAE,oBAAoB,EAAE,uBAAuB;YAClE,aAAa,EAAE,WAAW,EAAE,eAAe;SAC5C,CAAC;QAEF,oCAAoC;QACpC,MAAM,WAAW,GAAG;YAClB,uBAAuB,EAAE,sBAAsB,EAAE,QAAQ;YACzD,aAAa,EAAE,kBAAkB;SAClC,CAAC;QAEF,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACvD,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACpD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,SAAoB,EAAE,WAAwB;QACnE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC9B,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC5D,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,0CAA0C;QAC1C,IAAI,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;YACnE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;YAC9C,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;QAChD,CAAC;QAED,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,oBAAoB;IAClD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB,CAAC,QAA+B;QACvD,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC9B,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACpD,CAAC;CACF"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { CrawlOptions, CrawlResult } from '../utils/website-crawler.js';
|
|
2
|
+
import { BrowserManager } from '../utils/browser-manager.js';
|
|
3
|
+
import { AccessibilityTestResult, WCAGLevel, ViolationSeverity } from '../types/accessibility.js';
|
|
4
|
+
export interface WebsiteTestOptions extends CrawlOptions {
|
|
5
|
+
/** WCAG level to test against */
|
|
6
|
+
wcagLevel?: WCAGLevel;
|
|
7
|
+
/** Whether to perform full analysis */
|
|
8
|
+
fullAnalysis?: boolean;
|
|
9
|
+
/** Maximum concurrent tests */
|
|
10
|
+
concurrency?: number;
|
|
11
|
+
/** Whether to continue testing if individual pages fail */
|
|
12
|
+
continueOnError?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface PageTestResult {
|
|
15
|
+
/** URL that was tested */
|
|
16
|
+
url: string;
|
|
17
|
+
/** Whether the test was successful */
|
|
18
|
+
success: boolean;
|
|
19
|
+
/** Test result if successful */
|
|
20
|
+
result?: AccessibilityTestResult;
|
|
21
|
+
/** Error message if failed */
|
|
22
|
+
error?: string;
|
|
23
|
+
/** Test duration in milliseconds */
|
|
24
|
+
duration: number;
|
|
25
|
+
}
|
|
26
|
+
export interface WebsiteTestResult {
|
|
27
|
+
/** Website base URL */
|
|
28
|
+
baseUrl: string;
|
|
29
|
+
/** Timestamp when testing started */
|
|
30
|
+
timestamp: string;
|
|
31
|
+
/** Total duration of the entire test */
|
|
32
|
+
totalDuration: number;
|
|
33
|
+
/** Crawl results */
|
|
34
|
+
crawlResult: CrawlResult;
|
|
35
|
+
/** Results for each page tested */
|
|
36
|
+
pageResults: PageTestResult[];
|
|
37
|
+
/** Aggregated summary across all pages */
|
|
38
|
+
summary: WebsiteSummary;
|
|
39
|
+
/** Configuration used for testing */
|
|
40
|
+
testOptions: WebsiteTestOptions;
|
|
41
|
+
}
|
|
42
|
+
export interface WebsiteSummary {
|
|
43
|
+
/** Total pages tested successfully */
|
|
44
|
+
totalPages: number;
|
|
45
|
+
/** Total pages that failed to test */
|
|
46
|
+
failedPages: number;
|
|
47
|
+
/** Total violations across all pages */
|
|
48
|
+
totalViolations: number;
|
|
49
|
+
/** Violations by severity across all pages */
|
|
50
|
+
violationsBySeverity: Record<ViolationSeverity, number>;
|
|
51
|
+
/** Most common violations across the site */
|
|
52
|
+
commonViolations: Array<{
|
|
53
|
+
id: string;
|
|
54
|
+
description: string;
|
|
55
|
+
count: number;
|
|
56
|
+
affectedPages: number;
|
|
57
|
+
impact: ViolationSeverity;
|
|
58
|
+
}>;
|
|
59
|
+
/** Pages with the most violations */
|
|
60
|
+
problematicPages: Array<{
|
|
61
|
+
url: string;
|
|
62
|
+
violationCount: number;
|
|
63
|
+
score: number;
|
|
64
|
+
}>;
|
|
65
|
+
/** Overall site accessibility score */
|
|
66
|
+
overallScore: number;
|
|
67
|
+
/** WCAG compliance status */
|
|
68
|
+
compliance: Record<WCAGLevel, boolean>;
|
|
69
|
+
/** Performance metrics */
|
|
70
|
+
performance: {
|
|
71
|
+
averagePageTestTime: number;
|
|
72
|
+
crawlTime: number;
|
|
73
|
+
testTime: number;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export declare class WebsiteAccessibilityTester {
|
|
77
|
+
private readonly logger;
|
|
78
|
+
private readonly browserManager;
|
|
79
|
+
private readonly crawler;
|
|
80
|
+
private readonly accessibilityTester;
|
|
81
|
+
constructor(browserManager: BrowserManager);
|
|
82
|
+
/**
|
|
83
|
+
* Test accessibility for an entire website
|
|
84
|
+
*/
|
|
85
|
+
testWebsite(baseUrl: string, options?: WebsiteTestOptions): Promise<WebsiteTestResult>;
|
|
86
|
+
/**
|
|
87
|
+
* Test multiple pages with controlled concurrency
|
|
88
|
+
*/
|
|
89
|
+
private testPages;
|
|
90
|
+
/**
|
|
91
|
+
* Test a single page for accessibility
|
|
92
|
+
*/
|
|
93
|
+
private testSinglePage;
|
|
94
|
+
/**
|
|
95
|
+
* Generate aggregated website summary from individual page results
|
|
96
|
+
*/
|
|
97
|
+
private generateWebsiteSummary;
|
|
98
|
+
/**
|
|
99
|
+
* Split array into chunks of specified size
|
|
100
|
+
*/
|
|
101
|
+
private chunkArray;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=website-accessibility-tester.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"website-accessibility-tester.d.ts","sourceRoot":"","sources":["../../src/tools/website-accessibility-tester.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { AccessibilityTester } from './accessibility-tester.js';
|
|
2
|
+
import { WebsiteCrawler } from '../utils/website-crawler.js';
|
|
3
|
+
import { Logger } from '../utils/logger.js';
|
|
4
|
+
export class WebsiteAccessibilityTester {
|
|
5
|
+
logger;
|
|
6
|
+
browserManager;
|
|
7
|
+
crawler;
|
|
8
|
+
accessibilityTester;
|
|
9
|
+
constructor(browserManager) {
|
|
10
|
+
this.logger = new Logger().child({ component: 'WebsiteAccessibilityTester' });
|
|
11
|
+
this.browserManager = browserManager;
|
|
12
|
+
this.crawler = new WebsiteCrawler(browserManager);
|
|
13
|
+
this.accessibilityTester = new AccessibilityTester(browserManager);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Test accessibility for an entire website
|
|
17
|
+
*/
|
|
18
|
+
async testWebsite(baseUrl, options = {}) {
|
|
19
|
+
const startTime = Date.now();
|
|
20
|
+
const { wcagLevel = 'AA', fullAnalysis = false, concurrency = 3, continueOnError = true, ...crawlOptions } = options;
|
|
21
|
+
this.logger.info('Starting website accessibility test', {
|
|
22
|
+
baseUrl,
|
|
23
|
+
wcagLevel,
|
|
24
|
+
fullAnalysis,
|
|
25
|
+
concurrency
|
|
26
|
+
});
|
|
27
|
+
try {
|
|
28
|
+
// Step 1: Crawl the website to discover pages
|
|
29
|
+
this.logger.info('Crawling website to discover pages');
|
|
30
|
+
const crawlResult = await this.crawler.crawlWebsite(baseUrl, crawlOptions);
|
|
31
|
+
this.logger.info(`Discovered ${crawlResult.urls.length} pages to test`);
|
|
32
|
+
// Step 2: Test each discovered page
|
|
33
|
+
const testStartTime = Date.now();
|
|
34
|
+
const pageResults = await this.testPages(crawlResult.urls, wcagLevel, fullAnalysis, concurrency, continueOnError);
|
|
35
|
+
const testDuration = Date.now() - testStartTime;
|
|
36
|
+
// Step 3: Generate aggregated summary
|
|
37
|
+
const summary = this.generateWebsiteSummary(pageResults, crawlResult.crawlDuration, testDuration);
|
|
38
|
+
const totalDuration = Date.now() - startTime;
|
|
39
|
+
const result = {
|
|
40
|
+
baseUrl,
|
|
41
|
+
timestamp: new Date().toISOString(),
|
|
42
|
+
totalDuration,
|
|
43
|
+
crawlResult,
|
|
44
|
+
pageResults,
|
|
45
|
+
summary,
|
|
46
|
+
testOptions: options
|
|
47
|
+
};
|
|
48
|
+
this.logger.info('Website accessibility test completed', {
|
|
49
|
+
totalPages: summary.totalPages,
|
|
50
|
+
failedPages: summary.failedPages,
|
|
51
|
+
totalViolations: summary.totalViolations,
|
|
52
|
+
overallScore: summary.overallScore,
|
|
53
|
+
duration: totalDuration
|
|
54
|
+
});
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
this.logger.error('Website accessibility test failed', error instanceof Error ? error : new Error(String(error)));
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Test multiple pages with controlled concurrency
|
|
64
|
+
*/
|
|
65
|
+
async testPages(urls, wcagLevel, fullAnalysis, concurrency, continueOnError) {
|
|
66
|
+
const results = [];
|
|
67
|
+
const chunks = this.chunkArray(urls, concurrency);
|
|
68
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
69
|
+
const chunk = chunks[i];
|
|
70
|
+
if (!chunk)
|
|
71
|
+
continue;
|
|
72
|
+
this.logger.info(`Testing batch ${i + 1}/${chunks.length} (${chunk.length} pages)`);
|
|
73
|
+
const chunkPromises = chunk.map(url => this.testSinglePage(url, wcagLevel, fullAnalysis, continueOnError));
|
|
74
|
+
const chunkResults = await Promise.all(chunkPromises);
|
|
75
|
+
results.push(...chunkResults);
|
|
76
|
+
// Add a small delay between batches to be respectful
|
|
77
|
+
if (i < chunks.length - 1) {
|
|
78
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return results;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Test a single page for accessibility
|
|
85
|
+
*/
|
|
86
|
+
async testSinglePage(url, wcagLevel, fullAnalysis, continueOnError) {
|
|
87
|
+
const startTime = Date.now();
|
|
88
|
+
try {
|
|
89
|
+
this.logger.debug(`Testing page: ${url}`);
|
|
90
|
+
const result = await this.accessibilityTester.testTarget({
|
|
91
|
+
target: url,
|
|
92
|
+
type: 'url',
|
|
93
|
+
wcagLevel,
|
|
94
|
+
level: fullAnalysis ? 'full' : 'basic'
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
url,
|
|
98
|
+
success: true,
|
|
99
|
+
result,
|
|
100
|
+
duration: Date.now() - startTime
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
105
|
+
this.logger.warn(`Failed to test page: ${url}`, { error: errorMessage });
|
|
106
|
+
if (!continueOnError) {
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
url,
|
|
111
|
+
success: false,
|
|
112
|
+
error: errorMessage,
|
|
113
|
+
duration: Date.now() - startTime
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Generate aggregated website summary from individual page results
|
|
119
|
+
*/
|
|
120
|
+
generateWebsiteSummary(pageResults, crawlTime, testTime) {
|
|
121
|
+
const successfulResults = pageResults.filter(r => r.success && r.result);
|
|
122
|
+
const failedResults = pageResults.filter(r => !r.success);
|
|
123
|
+
// Aggregate violations
|
|
124
|
+
const allViolations = [];
|
|
125
|
+
const violationsBySeverity = {
|
|
126
|
+
critical: 0,
|
|
127
|
+
serious: 0,
|
|
128
|
+
moderate: 0,
|
|
129
|
+
minor: 0
|
|
130
|
+
};
|
|
131
|
+
let totalScore = 0;
|
|
132
|
+
const pageScores = [];
|
|
133
|
+
for (const pageResult of successfulResults) {
|
|
134
|
+
if (pageResult.result) {
|
|
135
|
+
allViolations.push(...pageResult.result.violations);
|
|
136
|
+
// Aggregate severity counts
|
|
137
|
+
for (const violation of pageResult.result.violations) {
|
|
138
|
+
violationsBySeverity[violation.impact]++;
|
|
139
|
+
}
|
|
140
|
+
totalScore += pageResult.result.summary.score;
|
|
141
|
+
pageScores.push({
|
|
142
|
+
url: pageResult.url,
|
|
143
|
+
score: pageResult.result.summary.score,
|
|
144
|
+
violationCount: pageResult.result.violations.length
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Calculate common violations
|
|
149
|
+
const violationCounts = new Map();
|
|
150
|
+
for (const pageResult of successfulResults) {
|
|
151
|
+
if (pageResult.result) {
|
|
152
|
+
for (const violation of pageResult.result.violations) {
|
|
153
|
+
const existing = violationCounts.get(violation.id);
|
|
154
|
+
if (existing) {
|
|
155
|
+
existing.count++;
|
|
156
|
+
existing.affectedPages.add(pageResult.url);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
violationCounts.set(violation.id, {
|
|
160
|
+
id: violation.id,
|
|
161
|
+
description: violation.description,
|
|
162
|
+
count: 1,
|
|
163
|
+
affectedPages: new Set([pageResult.url]),
|
|
164
|
+
impact: violation.impact
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const commonViolations = Array.from(violationCounts.values())
|
|
171
|
+
.map(v => ({
|
|
172
|
+
id: v.id,
|
|
173
|
+
description: v.description,
|
|
174
|
+
count: v.count,
|
|
175
|
+
affectedPages: v.affectedPages.size,
|
|
176
|
+
impact: v.impact
|
|
177
|
+
}))
|
|
178
|
+
.sort((a, b) => b.count - a.count)
|
|
179
|
+
.slice(0, 10);
|
|
180
|
+
// Find most problematic pages
|
|
181
|
+
const problematicPages = pageScores
|
|
182
|
+
.sort((a, b) => b.violationCount - a.violationCount || a.score - b.score)
|
|
183
|
+
.slice(0, 10);
|
|
184
|
+
// Calculate overall score
|
|
185
|
+
const overallScore = successfulResults.length > 0 ? totalScore / successfulResults.length : 0;
|
|
186
|
+
// Calculate compliance
|
|
187
|
+
const compliance = {
|
|
188
|
+
A: true,
|
|
189
|
+
AA: true,
|
|
190
|
+
AAA: true
|
|
191
|
+
};
|
|
192
|
+
for (const pageResult of successfulResults) {
|
|
193
|
+
if (pageResult.result) {
|
|
194
|
+
const pageCompliance = pageResult.result.summary.compliance;
|
|
195
|
+
compliance.A = compliance.A && pageCompliance.A;
|
|
196
|
+
compliance.AA = compliance.AA && pageCompliance.AA;
|
|
197
|
+
compliance.AAA = compliance.AAA && pageCompliance.AAA;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
totalPages: successfulResults.length,
|
|
202
|
+
failedPages: failedResults.length,
|
|
203
|
+
totalViolations: allViolations.length,
|
|
204
|
+
violationsBySeverity,
|
|
205
|
+
commonViolations,
|
|
206
|
+
problematicPages,
|
|
207
|
+
overallScore: Math.round(overallScore * 100) / 100,
|
|
208
|
+
compliance,
|
|
209
|
+
performance: {
|
|
210
|
+
averagePageTestTime: pageResults.length > 0 ?
|
|
211
|
+
pageResults.reduce((sum, r) => sum + r.duration, 0) / pageResults.length : 0,
|
|
212
|
+
crawlTime,
|
|
213
|
+
testTime
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Split array into chunks of specified size
|
|
219
|
+
*/
|
|
220
|
+
chunkArray(array, size) {
|
|
221
|
+
const chunks = [];
|
|
222
|
+
for (let i = 0; i < array.length; i += size) {
|
|
223
|
+
chunks.push(array.slice(i, i + size));
|
|
224
|
+
}
|
|
225
|
+
return chunks;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=website-accessibility-tester.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"website-accessibility-tester.js","sourceRoot":"","sources":["../../src/tools/website-accessibility-tester.ts"],"names":[],"mappings":"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"}
|