// Website Validation Script const validateWebsite = { // Critical paths that must exist and be accessible criticalPaths: [ '/', '/projects', '/papers', '/proposals', '/docs' ], // Project paths projectPaths: [ '/projects/automedical', '/projects/analytics', '/projects/autoglaucoma' ], // Paper paths paperPaths: [ '/papers/fermed-vlm', '/papers/archive/research', '/papers/archive/publications' ], // Proposal paths proposalPaths: [ '/proposals/nhs/main', '/proposals/nhs/detailed', '/proposals/nhs/formal' ], // Documentation paths docPaths: [ '/docs/main', '/docs/api', '/docs/deployment' ], // Validate all links async validateLinks() { const results = { working: [], redirects: [], broken: [] }; const allPaths = [ ...this.criticalPaths, ...this.projectPaths, ...this.paperPaths, ...this.proposalPaths, ...this.docPaths ]; for (const path of allPaths) { try { const response = await fetch(path); if (response.ok) { if (response.redirected) { results.redirects.push({ path, redirectTo: response.url }); } else { results.working.push(path); } } else { results.broken.push({ path, status: response.status }); } } catch (error) { results.broken.push({ path, error: error.message }); } } return results; }, // Validate navigation consistency validateNavigation() { const results = { consistent: true, errors: [] }; // Check if all pages have navigation document.querySelectorAll('nav').forEach(nav => { const links = nav.querySelectorAll('a'); const requiredLinks = ['Home', 'Projects', 'Papers', 'Proposals', 'Documentation']; const missingLinks = requiredLinks.filter(required => ![...links].some(link => link.textContent.trim().toLowerCase() === required.toLowerCase() ) ); if (missingLinks.length > 0) { results.consistent = false; results.errors.push({ page: window.location.pathname, missingLinks }); } }); return results; }, // Validate breadcrumbs validateBreadcrumbs() { const results = { valid: true, errors: [] }; document.querySelectorAll('.breadcrumb').forEach(breadcrumb => { const links = breadcrumb.querySelectorAll('a'); const currentPath = window.location.pathname; const pathParts = currentPath.split('/').filter(Boolean); // First link should always be Home if (links[0]?.getAttribute('href') !== '/') { results.valid = false; results.errors.push({ page: currentPath, error: 'Missing home link in breadcrumb' }); } // Check if breadcrumb matches current path pathParts.forEach((part, index) => { const link = links[index + 1]; if (!link || !link.getAttribute('href').includes(part)) { results.valid = false; results.errors.push({ page: currentPath, error: `Invalid breadcrumb path at level ${index + 1}` }); } }); }); return results; }, // Generate validation report async generateReport() { const linkResults = await this.validateLinks(); const navResults = this.validateNavigation(); const breadcrumbResults = this.validateBreadcrumbs(); return { timestamp: new Date().toISOString(), links: { total: linkResults.working.length + linkResults.redirects.length + linkResults.broken.length, working: linkResults.working.length, redirects: linkResults.redirects.length, broken: linkResults.broken.length, details: linkResults }, navigation: { consistent: navResults.consistent, errors: navResults.errors }, breadcrumbs: { valid: breadcrumbResults.valid, errors: breadcrumbResults.errors } }; } }; // Export for use in Node.js environments if (typeof module !== 'undefined' && module.exports) { module.exports = validateWebsite; } // For browser use if (typeof window !== 'undefined') { window.validateWebsite = validateWebsite; }