const { chromium } = require('playwright'); const fs = require('fs'); const path = require('path'); const TARGET_URL = process.env.TARGET_URL; const PAGES = (process.env.PAGES || '/').split(',').map(p => p.trim()); const REPORTS_DIR = process.env.REPORTS_DIR || './reports'; async function collectLinks(page, pagePath) { const fullUrl = `${TARGET_URL}${pagePath}`; await page.goto(fullUrl, { waitUntil: 'networkidle', timeout: 30000 }); return page.evaluate(() => Array.from(document.querySelectorAll('a[href]')) .map(a => a.href)); } async function checkLink(context, url) { try { const resp = await context.request.fetch(url, { method: 'HEAD', timeout: 15000 }); return { url, status: resp.status(), ok: resp.ok() }; } catch (err) { return { url, status: 0, ok: false, error: err.message }; } } async function main() { if (!TARGET_URL) { console.error('TARGET_URL environment variable is required'); process.exit(1); } const browser = await chromium.launch({ headless: true }); const context = await browser.newContext(); const results = []; try { for (const pagePath of PAGES) { const page = await context.newPage(); try { const links = await collectLinks(page, pagePath); await page.close(); const checked = []; for (const url of [...new Set(links)]) { if (url.startsWith('mailto:') || url.startsWith('tel:')) continue; checked.push(await checkLink(context, url)); } const broken = checked.filter(c => !c.ok); results.push({ pagePath, total: checked.length, broken: broken.length, brokenLinks: broken }); console.log(`${pagePath}: ${checked.length} links, ${broken.length} broken`); } catch (err) { results.push({ pagePath, error: err.message, total: 0, broken: 0, brokenLinks: [] }); console.error(`Failed ${pagePath}: ${err.message}`); } finally { await page.close().catch(() => {}); } } } finally { await browser.close(); } const totalBroken = results.reduce((s, r) => s + r.broken, 0); const report = { timestamp: new Date().toISOString(), targetUrl: TARGET_URL, pages: PAGES, summary: { totalPages: results.length, totalBroken, hasBroken: totalBroken > 0 }, results, }; fs.mkdirSync(REPORTS_DIR, { recursive: true }); const reportPath = path.join(REPORTS_DIR, 'link-check-report.json'); fs.writeFileSync(reportPath, JSON.stringify(report, null, 2)); console.log(`Report saved to ${reportPath}`); if (totalBroken > 0) { console.error(`Found ${totalBroken} broken links`); process.exit(1); } } main().catch(err => { console.error('Fatal error:', err); process.exit(1); });