Files
telegram-shop/tests/scripts/link-checker.js
NW 8d85776135 feat: add AI-powered visual regression testing infrastructure
- Add docker-compose.web-testing.yml with vlmkit service
- Add 5 test scripts: capture, compare, pipeline, console-monitor, link-checker
- Add vrt.config.json with 3 viewports + maskSelectors
- Add package.json with @mizchi/vlmkit and Node >=24
- Add tests/README.md with VRT documentation
- Update .gitignore for test artifacts

Based on APAW issue #144 / milestone #106
2026-06-30 21:09:30 +01:00

83 lines
2.7 KiB
JavaScript

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);
});