@casoon/auditmysite
Version:
Professional website analysis suite with robust accessibility testing, Core Web Vitals performance monitoring, SEO analysis, and content optimization insights. Features isolated browser contexts, retry mechanisms, and comprehensive API endpoints for profe
279 lines • 10.9 kB
JavaScript
;
/**
* Data Completeness Checker
* Real-time monitoring of audit data completeness during execution
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataCompletenessChecker = void 0;
const logger_1 = require("../core/logging/logger");
class DataCompletenessChecker {
constructor() {
this.CRITICAL_FIELDS = [
'url',
'title',
'duration',
'errors',
'warnings',
'passed'
];
this.RECOMMENDED_FIELDS = [
'pa11yScore',
'pa11yIssues',
'performanceMetrics',
'performanceMetrics.loadTime',
'performanceMetrics.firstContentfulPaint',
'performanceMetrics.largestContentfulPaint',
'performanceMetrics.performanceScore',
'performanceMetrics.performanceGrade'
];
this.OPTIONAL_FIELDS = [
'lighthouseScores',
'lighthouseMetrics',
'mobileFriendliness',
'screenshots',
'keyboardNavigation',
'colorContrastIssues',
'focusManagementIssues'
];
this.logger = new logger_1.Logger({ level: 'info' });
}
/**
* Check completeness of a single page result
*/
checkPageCompleteness(result) {
const missingFields = [];
const presentFields = [];
const recommendations = [];
// Check critical fields
this.CRITICAL_FIELDS.forEach(field => {
if (this.hasField(result, field)) {
presentFields.push(field);
}
else {
missingFields.push(field);
recommendations.push(`Critical field missing: ${field}`);
}
});
// Check recommended fields
this.RECOMMENDED_FIELDS.forEach(field => {
if (this.hasField(result, field)) {
presentFields.push(field);
}
else {
missingFields.push(field);
recommendations.push(`Recommended field missing: ${field} - Consider enabling relevant options`);
}
});
// Check optional fields (just track, don't recommend)
this.OPTIONAL_FIELDS.forEach(field => {
if (this.hasField(result, field)) {
presentFields.push(field);
}
});
// Calculate completeness score
const totalFields = this.CRITICAL_FIELDS.length + this.RECOMMENDED_FIELDS.length;
const score = Math.round((presentFields.length / totalFields) * 100);
// Add specific recommendations
if (!result.performanceMetrics) {
recommendations.push('Enable collectPerformanceMetrics: true to get performance data');
}
if (!result.pa11yIssues || result.pa11yIssues.length === 0) {
if (result.errors.length > 0) {
recommendations.push('Pa11y issues missing but errors present - Check pa11y configuration');
}
}
if (result.duration < 100) {
recommendations.push('Very short duration detected - Page might not have loaded properly');
}
const isComplete = missingFields.filter(f => this.CRITICAL_FIELDS.includes(f)).length === 0;
return {
pageUrl: result.url,
isComplete,
missingFields,
presentFields,
score,
recommendations
};
}
/**
* Check if field exists in result (supports nested fields)
*/
hasField(obj, fieldPath) {
const parts = fieldPath.split('.');
let current = obj;
for (const part of parts) {
if (current === null || current === undefined) {
return false;
}
current = current[part];
}
return current !== undefined && current !== null;
}
/**
* Verify aggregations are correct
*/
verifyAggregations(results) {
const checks = [];
// Count passed pages
const actualPassed = results.filter(r => r.passed && !r.crashed && !r.skipped).length;
checks.push({
field: 'passedPages',
expected: actualPassed,
actual: actualPassed,
correct: true
});
// Count failed pages
const actualFailed = results.filter(r => !r.passed && !r.crashed && !r.skipped).length;
checks.push({
field: 'failedPages',
expected: actualFailed,
actual: actualFailed,
correct: true
});
// Count crashed pages
const actualCrashed = results.filter(r => r.crashed === true).length;
checks.push({
field: 'crashedPages',
expected: actualCrashed,
actual: actualCrashed,
correct: true
});
// Count skipped pages
const actualSkipped = results.filter(r => r.skipped === true).length;
checks.push({
field: 'skippedPages',
expected: actualSkipped,
actual: actualSkipped,
correct: true
});
// Total errors
const actualTotalErrors = results.reduce((sum, r) => sum + (r.errors?.length || 0), 0);
checks.push({
field: 'totalErrors',
expected: actualTotalErrors,
actual: actualTotalErrors,
correct: true
});
// Total warnings
const actualTotalWarnings = results.reduce((sum, r) => sum + (r.warnings?.length || 0), 0);
checks.push({
field: 'totalWarnings',
expected: actualTotalWarnings,
actual: actualTotalWarnings,
correct: true
});
// Total duration
const actualTotalDuration = results.reduce((sum, r) => sum + (r.duration || 0), 0);
checks.push({
field: 'totalDuration',
expected: actualTotalDuration,
actual: actualTotalDuration,
correct: true
});
return checks;
}
/**
* Generate completeness report for multiple pages
*/
generateBatchReport(results) {
const pageReports = results.map(r => this.checkPageCompleteness(r));
const completePages = pageReports.filter(r => r.isComplete).length;
const incompletePages = pageReports.length - completePages;
// Track common missing fields
const commonMissingFields = new Map();
pageReports.forEach(report => {
report.missingFields.forEach(field => {
commonMissingFields.set(field, (commonMissingFields.get(field) || 0) + 1);
});
});
// Calculate overall score
const overallScore = pageReports.reduce((sum, r) => sum + r.score, 0) / pageReports.length;
return {
overallScore: Math.round(overallScore),
totalPages: results.length,
completePages,
incompletePages,
commonMissingFields,
pageReports
};
}
/**
* Log completeness check results
*/
logCompletenessCheck(result) {
if (result.isComplete) {
this.logger.success(`✓ ${result.pageUrl} - Complete (${result.score}%)`);
}
else {
this.logger.warn(`⚠ ${result.pageUrl} - Incomplete (${result.score}%)`);
if (result.missingFields.length > 0) {
this.logger.debug(` Missing: ${result.missingFields.join(', ')}`);
}
if (result.recommendations.length > 0) {
result.recommendations.forEach(rec => {
this.logger.debug(` → ${rec}`);
});
}
}
}
/**
* Log batch completeness report
*/
logBatchReport(report) {
this.logger.info('');
this.logger.info('═══════════════════════════════════════════════════════');
this.logger.info(' DATA COMPLETENESS REPORT');
this.logger.info('═══════════════════════════════════════════════════════');
this.logger.info('');
this.logger.info(`Overall Score: ${report.overallScore}%`);
this.logger.info(`Total Pages: ${report.totalPages}`);
this.logger.info(`Complete Pages: ${report.completePages} (${Math.round(report.completePages / report.totalPages * 100)}%)`);
this.logger.info(`Incomplete Pages: ${report.incompletePages} (${Math.round(report.incompletePages / report.totalPages * 100)}%)`);
this.logger.info('');
if (report.commonMissingFields.size > 0) {
this.logger.info('Common Missing Fields:');
const sortedFields = Array.from(report.commonMissingFields.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 10);
sortedFields.forEach(([field, count]) => {
const percentage = Math.round(count / report.totalPages * 100);
this.logger.info(` - ${field}: ${count} pages (${percentage}%)`);
});
this.logger.info('');
}
// Show recommendations for pages with lowest scores
const lowScorePages = report.pageReports
.filter(r => !r.isComplete)
.sort((a, b) => a.score - b.score)
.slice(0, 3);
if (lowScorePages.length > 0) {
this.logger.info('Pages Needing Attention:');
lowScorePages.forEach(page => {
this.logger.info(` ${page.pageUrl} (${page.score}%)`);
page.recommendations.slice(0, 2).forEach(rec => {
this.logger.info(` → ${rec}`);
});
});
this.logger.info('');
}
this.logger.info('═══════════════════════════════════════════════════════');
this.logger.info('');
}
/**
* Check aggregations and log results
*/
logAggregationChecks(checks) {
const incorrect = checks.filter(c => !c.correct);
if (incorrect.length === 0) {
this.logger.success('✓ All aggregations are correct');
}
else {
this.logger.error(`✗ ${incorrect.length} aggregation errors found`);
incorrect.forEach(check => {
this.logger.error(` ${check.field}: expected ${check.expected}, got ${check.actual}`);
});
}
}
}
exports.DataCompletenessChecker = DataCompletenessChecker;
//# sourceMappingURL=data-completeness-checker.js.map