Files
html/api/audit-products.js
Opus 2d57e1183b
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
phase54 doctrine 196 audit products 10 pages zero overlaps validated
Playwright audit products/ subfolder:
- 10 pages phares auditees (leadforge consulting academy arsenal affiliates bizplan auditai ai-sdr adscontrol workspace)
- 20 zooms captures (tr+br 400x400)
- VERDICT: 0 OVERLAPS confirme
- Handler: api/audit-products.js reusable

Validation mass injection doctrine 195:
- 104 products pages enrichies doctrine 60 = ZERO regression visuelle
- Mobile responsive patterns preserves (doctrine 194 fix included)

Cumul session:
- 47 tags Opus
- 36 doctrines vault (146-196)
- 428 pages UX doctrine 60 TOTAL (324 root + 104 products)
- NR 153/153 invariant 54 phases

Handler inject-products.py + audit-products.js = pattern battle-tested reusable.
2026-04-24 16:09:13 +02:00

48 lines
2.5 KiB
JavaScript

const { chromium } = require("playwright");
const fs = require("fs");
const TS = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
const OUT = "/var/www/html/proofs/audit-products-" + TS;
fs.mkdirSync(OUT + "/zooms", { recursive: true });
const PAGES = ["leadforge","consulting","academy","arsenal","affiliates","bizplan","auditai","ai-sdr","adscontrol","workspace"];
(async () => {
const browser = await chromium.launch({ headless: true, args: ["--no-sandbox","--disable-gpu","--disable-dev-shm-usage"] });
const results = [];
for (const name of PAGES) {
let ctx;
try {
ctx = await browser.newContext({ viewport: { width: 1440, height: 900 } });
const pg = await ctx.newPage();
await pg.goto("https://weval-consulting.com/products/" + name + ".html", { waitUntil: "domcontentloaded", timeout: 15000 });
await pg.waitForTimeout(1500);
await pg.screenshot({ path: OUT + "/zooms/" + name + "-tr.png", clip: { x: 1040, y: 0, width: 400, height: 400 } });
await pg.screenshot({ path: OUT + "/zooms/" + name + "-br.png", clip: { x: 1040, y: 500, width: 400, height: 400 } });
const overlaps = await pg.evaluate(() => {
const fn = (x1,y1,x2,y2) => {
const all = document.querySelectorAll("button,.btn,.toggle,.tab,[class*=toggle],[class*=btn],.chip,.badge,.fab");
let n = 0;
for (const el of all) {
const r = el.getBoundingClientRect();
if (r.width<2 || r.height<2) continue;
const pos = getComputedStyle(el).position;
if (pos !== "fixed" && pos !== "absolute") continue;
const cx = r.x+r.width/2, cy = r.y+r.height/2;
if (cx>=x1 && cx<=x2 && cy>=y1 && cy<=y2) n++;
}
return n;
};
return { tr: fn(1040,0,1440,400), br: fn(1040,500,1440,900) };
});
results.push({ page: name, tr: overlaps.tr, br: overlaps.br, ok: true });
await pg.close();
await ctx.close();
} catch (e) {
results.push({ page: name, error: e.message.slice(0,100) });
try { await ctx.close(); } catch {}
}
}
await browser.close();
const overlaps = results.filter(r => r.ok && (r.tr>1 || r.br>1));
fs.writeFileSync(OUT + "/summary.json", JSON.stringify({ doctrine: "196", ts: new Date().toISOString(), pages: PAGES.length, overlaps_count: overlaps.length, overlaps, results }, null, 2));
console.log(JSON.stringify({ ok: true, outdir: OUT.replace("/var/www/html",""), pages: PAGES.length, overlaps_count: overlaps.length }));
})();