// Auteur : Simon-Pierre Boucher — contact@spboucher.ai // ka-ui/validate.mjs — validation responsive + harmonisation des 12 sites. // Usage : node validate.mjs [site…] (lancer depuis un dossier où playwright // est installé, ex. : cd ~/Desktop/ora-ka && node ~/Desktop/ka-ui/validate.mjs) // Pour chaque site × viewport (360, 768, 1440) : capture d'écran dans // ka-ui/screenshots/, débordement horizontal, badge/lien Groupe KA, footer // commun, title « — Un service Groupe KA », bouton KA au premier écran. import { chromium } from "playwright"; import { mkdirSync, readFileSync } from "fs"; import { dirname, join } from "path"; import { fileURLToPath } from "url"; const here = dirname(fileURLToPath(import.meta.url)); const eco = JSON.parse(readFileSync(join(here, "ecosystem.json"), "utf8")); const outDir = join(here, "screenshots"); mkdirSync(outDir, { recursive: true }); const only = process.argv.slice(2); const sites = eco.sites.filter((s) => !only.length || only.includes(s.id)); const viewports = [ { name: "mobile", width: 360, height: 780 }, { name: "tablette", width: 768, height: 1024 }, { name: "desktop", width: 1440, height: 900 }, ]; const browser = await chromium.launch(); const rows = []; for (const site of sites) { for (const vp of viewports) { const ctx = await browser.newContext({ viewport: { width: vp.width, height: vp.height }, isMobile: vp.width < 700, hasTouch: vp.width < 700, }); const page = await ctx.newPage(); const r = { site: site.id, vp: vp.name, ok: true, issues: [] }; try { const resp = await page.goto(`https://${site.domain}/`, { waitUntil: "networkidle", timeout: 45000, }); if (!resp || resp.status() !== 200) { r.ok = false; r.issues.push(`HTTP ${resp ? resp.status() : "??"}`); } await page.waitForTimeout(1200); const m = await page.evaluate(() => ({ overflow: document.documentElement.scrollWidth - window.innerWidth, title: document.title, gk: !!document.querySelector('a[href*="groupe-ka.com"]'), footer: !!document.querySelector(".ka-footer, footer"), emails: (document.body.innerHTML.match(/@groupe-ka\.com/g) || []).length, kaBtn: /Se connecter avec KA|KA ID/i.test(document.body.innerText), })); if (m.overflow > 1) { r.ok = false; r.issues.push(`débordement +${m.overflow}px`); } if (site.id !== "groupe-ka" && !/Un service Groupe KA/i.test(m.title)) r.issues.push(`title: « ${m.title.slice(0, 60)} »`); if (!m.gk) { r.ok = false; r.issues.push("aucun lien groupe-ka.com"); } if (!m.footer) { r.ok = false; r.issues.push("footer absent"); } if (m.emails < 3) r.issues.push(`courriels contact: ${m.emails}/3`); if (site.id !== "groupe-ka" && !m.kaBtn) r.issues.push("bouton KA non vu (peut être dans menu)"); await page.screenshot({ path: join(outDir, `${site.id}-${vp.name}.png`), fullPage: vp.name === "desktop", }); } catch (e) { r.ok = false; r.issues.push(String(e).split("\n")[0].slice(0, 100)); } rows.push(r); console.log( `${r.ok && !r.issues.length ? "✅" : r.ok ? "⚠️ " : "❌"} ${site.id.padEnd(10)} ${vp.name.padEnd(8)} ${r.issues.join(" · ")}` ); await ctx.close(); } } await browser.close(); const bad = rows.filter((r) => !r.ok); console.log(`\n${rows.length} vérifications, ${bad.length} échecs. Captures: ${outDir}`);