SPB Git forge

spb/uqo-eval

Public
55commits 2branches 0releases
134.4 MBsize
maindefault branch
3 h agolast push
TypeScript 90.1% JavaScript 3.2% Python 3.2% CSS 1.8% HTML 1.8%

WIP laptop non committé (17 fichiers), sauvegardé lors de la réorganisation du 2026-10-02

laptop committed 3 h ago (Oct 2, 2026) parent 08b3a13

17 changed files +293 −0

added scripts/ws-favicon-preview.mjs +12 −0
@@ -0,0 +1,12 @@
1 +import { chromium } from "playwright";
2 +import { readFileSync } from "node:fs";
3 +const svg = readFileSync("/Users/simon-pierreboucher/Desktop/Projets/apps-web/websensor/apps/web/src/app/icon.svg", "utf8");
4 +const b = await chromium.launch();
5 +const p = await (await b.newContext({ viewport: { width: 720, height: 260 }, deviceScaleFactor: 2 })).newPage();
6 +const tile = (s) => svg.replace(/width="64" height="64"/, `width="${s}" height="${s}"`);
7 +await p.setContent(`<html><body style="margin:0;padding:24px;background:#f3f4f6;font-family:Inter,system-ui;display:flex;gap:28px;align-items:center">
8 + ${tile(16)} ${tile(24)} ${tile(32)} ${tile(48)} ${tile(96)} ${tile(160)}
9 + <div style="display:flex;align-items:center;gap:8px;background:#fff;border:1px solid #ddd;border-radius:8px;padding:6px 12px;font-size:14px;color:#222">${tile(16)} WebSensor — The Web is changing. We are watching.</div>
10 +</body></html>`);
11 +await p.screenshot({ path: "/tmp/favicon-preview.png" });
12 +await b.close();
added scripts/ws-hydr.mjs +13 −0
@@ -0,0 +1,13 @@
1 +import { chromium } from "playwright";
2 +const b = await chromium.launch();
3 +const p = await (await b.newContext({ viewport: { width: 1440, height: 900 } })).newPage();
4 +const msgs = [];
5 +p.on("console", (m) => msgs.push(m.type() + ": " + m.text().slice(0, 300)));
6 +p.on("pageerror", (e) => msgs.push("PAGEERROR: " + e.message.slice(0, 300)));
7 +p.on("requestfailed", (r) => msgs.push("REQFAIL: " + r.url().slice(0, 160) + " " + (r.failure()?.errorText ?? "")));
8 +await p.goto("http://localhost:8260/", { waitUntil: "load", timeout: 90000 });
9 +await p.waitForTimeout(6000);
10 +const hydrated = await p.evaluate(() => Boolean(document.querySelector("[data-density]")));
11 +console.log("data-density set (PrefsProvider mounted):", hydrated);
12 +console.log(msgs.slice(0, 20).join("\n"));
13 +await b.close();
added scripts/ws-hydr.mjs.bak +13 −0
@@ -0,0 +1,13 @@
1 +import { chromium } from "playwright";
2 +const b = await chromium.launch();
3 +const p = await (await b.newContext({ viewport: { width: 1440, height: 900 } })).newPage();
4 +const msgs = [];
5 +p.on("console", (m) => msgs.push(m.type() + ": " + m.text().slice(0, 300)));
6 +p.on("pageerror", (e) => msgs.push("PAGEERROR: " + e.message.slice(0, 300)));
7 +p.on("requestfailed", (r) => msgs.push("REQFAIL: " + r.url().slice(0, 160) + " " + (r.failure()?.errorText ?? "")));
8 +await p.goto("http://localhost:8261/", { waitUntil: "load", timeout: 90000 });
9 +await p.waitForTimeout(6000);
10 +const hydrated = await p.evaluate(() => Boolean(document.querySelector("[data-density]")));
11 +console.log("data-density set (PrefsProvider mounted):", hydrated);
12 +console.log(msgs.slice(0, 20).join("\n"));
13 +await b.close();
added scripts/ws-hydr2.mjs +12 −0
@@ -0,0 +1,12 @@
1 +import { chromium } from "playwright";
2 +const b = await chromium.launch();
3 +const p = await (await b.newContext({ viewport: { width: 1440, height: 900 } })).newPage();
4 +const msgs = [];
5 +p.on("console", (m) => msgs.push(m.type() + ": " + m.text().slice(0, 400)));
6 +p.on("pageerror", (e) => msgs.push("PAGEERROR: " + e.message.slice(0, 400)));
7 +await p.goto(process.argv[2] ?? "http://localhost:8260/", { waitUntil: "load", timeout: 90000 });
8 +await p.waitForTimeout(8000);
9 +const info = await p.evaluate(() => ({ density: document.documentElement.dataset.density ?? null, hasNextData: Boolean(document.querySelector("script[src*='_next']")), reactRoot: Boolean(document.querySelector("#__next") || document.body.getAttribute("data-reactroot") !== null), overlay: Boolean(document.querySelector("nextjs-portal")), overlayText: document.querySelector("nextjs-portal")?.shadowRoot?.textContent?.slice(0, 600) ?? null }));
10 +console.log(JSON.stringify(info, null, 1));
11 +console.log(msgs.filter((m) => !/HMR|DevTools/.test(m)).slice(0, 15).join("\n"));
12 +await b.close();
added scripts/ws-icons.mjs +20 −0
@@ -0,0 +1,20 @@
1 +import { chromium } from "playwright";
2 +import { readFileSync, writeFileSync } from "node:fs";
3 +const svg = readFileSync("/Users/simon-pierreboucher/Desktop/Projets/apps-web/websensor/apps/web/src/app/icon.svg", "utf8");
4 +const b = await chromium.launch();
5 +async function render(size, out, pad = 0) {
6 + const ctx = await b.newContext({ viewport: { width: size, height: size }, deviceScaleFactor: 1 });
7 + const p = await ctx.newPage();
8 + const inner = size - pad * 2;
9 + await p.setContent(`<html><body style="margin:0;background:${pad ? "#0a0e15" : "transparent"};width:${size}px;height:${size}px;display:flex;align-items:center;justify-content:center">${svg.replace(/width="64" height="64"/, `width="${inner}" height="${inner}"`)}</body></html>`);
10 + await p.screenshot({ path: out, omitBackground: !pad, clip: { x: 0, y: 0, width: size, height: size } });
11 + await ctx.close();
12 +}
13 +const base = "/Users/simon-pierreboucher/Desktop/Projets/apps-web/websensor/apps/web";
14 +await render(180, `${base}/src/app/apple-icon.png`);
15 +await render(192, `${base}/public/icons/icon-192.png`);
16 +await render(512, `${base}/public/icons/icon-512.png`);
17 +await render(512, `${base}/public/icons/icon-512-maskable.png`, 64);
18 +for (const s of [16, 32, 48]) await render(s, `/tmp/fav-${s}.png`);
19 +await b.close();
20 +console.log("rendered");
added scripts/ws-interact-prod.mjs +30 −0
@@ -0,0 +1,30 @@
1 +import { chromium } from "playwright";
2 +const b = await chromium.launch();
3 +const p = await (await b.newContext({ viewport: { width: 1440, height: 900 }, colorScheme: "dark" })).newPage();
4 +const errors = [];
5 +p.on("pageerror", (e) => errors.push("pageerror: " + e.message.slice(0, 150)));
6 +await p.goto("https://www.websensor.io/", { waitUntil: "networkidle", timeout: 90000 });
7 +const live = await p.waitForSelector("section[aria-label] header span:has-text('LIVE')", { timeout: 20000 }).catch(() => null);
8 +console.log("feed:", live ? "LIVE" : "not live");
9 +await p.locator("article a[href^='/event/']").first().click();
10 +const dlg = await p.waitForSelector("[role=dialog]", { timeout: 15000 }).catch(() => null);
11 +console.log("drawer:", Boolean(dlg), "url:", p.url());
12 +await p.waitForTimeout(2000);
13 +const detailLoaded = await p.locator("[role=dialog] :text('Evidence')").count();
14 +console.log("drawer detail sections:", detailLoaded);
15 +await p.keyboard.press("Escape"); await p.waitForTimeout(300);
16 +console.log("drawer closed:", (await p.locator("[role=dialog]").count()) === 0);
17 +await p.keyboard.press("Meta+k"); await p.waitForSelector("[role=combobox]", { timeout: 5000 });
18 +await p.keyboard.type("anthropic"); await p.waitForTimeout(1500);
19 +const opts = await p.locator("[role=option]").count(); console.log("palette options:", opts);
20 +await p.keyboard.press("ArrowDown"); await p.keyboard.press("Enter"); await p.waitForTimeout(1500);
21 +console.log("after enter url:", p.url());
22 +await p.goto("https://www.websensor.io/", { waitUntil: "networkidle" });
23 +await p.locator("[role=radiogroup] button").first().click(); await p.waitForTimeout(300);
24 +console.log("density:", await p.evaluate(() => document.documentElement.dataset.density));
25 +await p.reload({ waitUntil: "networkidle" }); await p.waitForTimeout(1500);
26 +console.log("density persisted:", await p.evaluate(() => document.documentElement.dataset.density));
27 +await p.getByRole("button", { name: /Pause/ }).click(); await p.waitForTimeout(300);
28 +console.log("paused label:", await p.locator("section[aria-label] header span:has-text('PAUSED')").count());
29 +console.log("errors:", errors);
30 +await b.close();
added scripts/ws-interact.mjs.bak +45 −0
@@ -0,0 +1,45 @@
1 +import { chromium } from "playwright";
2 +const b = await chromium.launch();
3 +const ctx = await b.newContext({ viewport: { width: 1440, height: 900 }, colorScheme: "dark" });
4 +const p = await ctx.newPage();
5 +const errors = [];
6 +p.on("pageerror", (e) => errors.push("pageerror: " + e.message));
7 +p.on("console", (m) => { if (m.type() === "error") errors.push("console: " + m.text().slice(0, 200)); });
8 +await p.goto("http://localhost:8260/", { waitUntil: "networkidle", timeout: 90000 });
9 +const live = await p.waitForSelector("section[aria-label] header span:has-text('LIVE')", { timeout: 20000 }).catch(() => null);
10 +console.log("feed status:", live ? "LIVE" : "not live", "errors so far:", errors.slice(0,5));
11 +await p.waitForTimeout(500);
12 +await p.locator("article a[href^='/event/']").first().click();
13 +const dlg = await p.waitForSelector("[role=dialog]", { timeout: 15000 }).catch(() => null);
14 +console.log("drawer:", Boolean(dlg), "url:", p.url(), "errors:", errors.slice(0,5));
15 +if (!dlg) { await p.screenshot({ path: "/tmp/no-drawer.png" }); await b.close(); process.exit(0); }
16 +await p.waitForTimeout(2500);
17 +await p.screenshot({ path: "/tmp/drawer.png" });
18 +await p.keyboard.press("Escape");
19 +await p.waitForTimeout(300);
20 +await p.keyboard.press("Meta+k");
21 +await p.waitForSelector("[role=combobox]", { timeout: 5000 });
22 +await p.keyboard.type("openai pricing");
23 +await p.waitForTimeout(1500);
24 +await p.screenshot({ path: "/tmp/palette.png" });
25 +await p.keyboard.press("Escape");
26 +// density compact via prefs
27 +await p.locator("[role=radiogroup] button").first().click();
28 +await p.waitForTimeout(500);
29 +await p.screenshot({ path: "/tmp/compact.png" });
30 +// mobile
31 +const m = await b.newContext({ viewport: { width: 390, height: 844 }, colorScheme: "dark", isMobile: true, hasTouch: true });
32 +const mp = await m.newPage();
33 +await mp.goto("http://localhost:8260/live?silent_change=true", { waitUntil: "networkidle", timeout: 90000 });
34 +await mp.waitForTimeout(1000);
35 +const ov = await mp.evaluate(() => document.documentElement.scrollWidth - window.innerWidth);
36 +console.log("mobile /live overflow px:", ov);
37 +await mp.locator("article a[href^='/event/']").first().click();
38 +await mp.waitForSelector("[role=dialog]", { timeout: 15000 });
39 +await mp.waitForTimeout(2000);
40 +await mp.screenshot({ path: "/tmp/drawer-mobile.png" });
41 +await mp.getByRole("button", { name: "More" }).click().catch(() => {});
42 +await mp.waitForTimeout(600);
43 +await mp.screenshot({ path: "/tmp/more-mobile.png" });
44 +console.log("errors:", errors.slice(0, 8));
45 +await b.close();
added scripts/ws-interact2.mjs +30 −0
@@ -0,0 +1,30 @@
1 +import { chromium } from "playwright";
2 +const b = await chromium.launch();
3 +const p = await (await b.newContext({ viewport: { width: 1440, height: 900 }, colorScheme: "dark" })).newPage();
4 +const errors = [];
5 +p.on("pageerror", (e) => errors.push("pageerror: " + e.message.slice(0, 150)));
6 +await p.goto("http://localhost:8261/", { waitUntil: "networkidle", timeout: 90000 });
7 +const live = await p.waitForSelector("section[aria-label] header span:has-text('LIVE')", { timeout: 20000 }).catch(() => null);
8 +console.log("feed:", live ? "LIVE" : "not live");
9 +await p.locator("article a[href^='/event/']").first().click();
10 +const dlg = await p.waitForSelector("[role=dialog]", { timeout: 15000 }).catch(() => null);
11 +console.log("drawer:", Boolean(dlg), "url:", p.url());
12 +await p.waitForTimeout(2000);
13 +const detailLoaded = await p.locator("[role=dialog] :text('Evidence')").count();
14 +console.log("drawer detail sections:", detailLoaded);
15 +await p.keyboard.press("Escape"); await p.waitForTimeout(300);
16 +console.log("drawer closed:", (await p.locator("[role=dialog]").count()) === 0);
17 +await p.keyboard.press("Meta+k"); await p.waitForSelector("[role=combobox]", { timeout: 5000 });
18 +await p.keyboard.type("anthropic"); await p.waitForTimeout(1500);
19 +const opts = await p.locator("[role=option]").count(); console.log("palette options:", opts);
20 +await p.keyboard.press("ArrowDown"); await p.keyboard.press("Enter"); await p.waitForTimeout(1500);
21 +console.log("after enter url:", p.url());
22 +await p.goto("http://localhost:8261/", { waitUntil: "networkidle" });
23 +await p.locator("[role=radiogroup] button").first().click(); await p.waitForTimeout(300);
24 +console.log("density:", await p.evaluate(() => document.documentElement.dataset.density));
25 +await p.reload({ waitUntil: "networkidle" }); await p.waitForTimeout(1500);
26 +console.log("density persisted:", await p.evaluate(() => document.documentElement.dataset.density));
27 +await p.getByRole("button", { name: /Pause/ }).click(); await p.waitForTimeout(300);
28 +console.log("paused label:", await p.locator("section[aria-label] header span:has-text('PAUSED')").count());
29 +console.log("errors:", errors);
30 +await b.close();
added scripts/ws-nav.mjs +8 −0
@@ -0,0 +1,8 @@
1 +import { chromium } from "playwright";
2 +const b = await chromium.launch();
3 +const p = await (await b.newContext({ viewport: { width: 1440, height: 900 } })).newPage();
4 +let navs = 0; p.on("framenavigated", (f) => { if (f === p.mainFrame()) navs++; });
5 +await p.goto(process.argv[2], { waitUntil: "load", timeout: 90000 });
6 +await p.waitForTimeout(10000);
7 +console.log("main-frame navigations in 10 s:", navs);
8 +await b.close();
added scripts/ws-overflow2.mjs +16 −0
@@ -0,0 +1,16 @@
1 +import { chromium } from "playwright";
2 +const [,, url, w, h] = process.argv;
3 +const b = await chromium.launch();
4 +const p = await (await b.newContext({ viewport: { width: Number(w), height: Number(h) }, colorScheme: "dark" })).newPage();
5 +await p.goto(url, { waitUntil: "networkidle", timeout: 90000 });
6 +await p.waitForTimeout(1500);
7 +console.log(await p.evaluate(() => {
8 + const W = window.innerWidth; const out = [];
9 + const clipped = (el) => { for (let a = el.parentElement; a; a = a.parentElement) { const o = getComputedStyle(a).overflowX; if (o === "auto" || o === "scroll" || o === "hidden") return true; } return false; };
10 + for (const el of document.querySelectorAll("body *")) {
11 + const r = el.getBoundingClientRect();
12 + if ((r.right > W + 1 || el.scrollWidth > el.clientWidth + 1 && getComputedStyle(el).overflowX === "visible") && r.width > 0 && !clipped(el)) out.push(`${el.tagName.toLowerCase()}.${String(el.className).slice(0, 70)} right=${Math.round(r.right)} sw=${el.scrollWidth} cw=${el.clientWidth}`);
13 + }
14 + return `docWidth=${document.documentElement.scrollWidth} inner=${W}\n` + out.slice(0, 20).join("\n");
15 +}));
16 +await b.close();
added scripts/ws-overlay.mjs +13 −0
@@ -0,0 +1,13 @@
1 +import { chromium } from "playwright";
2 +const b = await chromium.launch();
3 +const p = await (await b.newContext({ viewport: { width: 1440, height: 900 } })).newPage();
4 +await p.goto(process.argv[2], { waitUntil: "load", timeout: 90000 });
5 +await p.waitForTimeout(12000);
6 +const info = await p.evaluate(() => {
7 + const portal = document.querySelector("nextjs-portal");
8 + const txt = portal?.shadowRoot?.textContent ?? "";
9 + const i = txt.search(/Error|Hydration|Unhandled|failed/i);
10 + return { density: document.documentElement.dataset.density ?? null, overlaySnippet: i >= 0 ? txt.slice(Math.max(0, i - 200), i + 900) : null, issues: txt.match(/\d+ Issues?/)?.[0] ?? null };
11 +});
12 +console.log(JSON.stringify(info, null, 1));
13 +await b.close();
added scripts/ws-req.mjs +12 −0
@@ -0,0 +1,12 @@
1 +import { chromium } from "playwright";
2 +const b = await chromium.launch();
3 +const p = await (await b.newContext({ viewport: { width: 1440, height: 900 } })).newPage();
4 +const pending = new Map(); const bad = [];
5 +p.on("request", (r) => pending.set(r.url(), Date.now()));
6 +p.on("response", (r) => { pending.delete(r.url()); if (r.status() >= 400) bad.push(r.status() + " " + r.url().slice(0, 140)); });
7 +p.on("requestfailed", (r) => { pending.delete(r.url()); bad.push("FAIL " + r.url().slice(0, 140) + " " + (r.failure()?.errorText ?? "")); });
8 +await p.goto("http://localhost:8260/", { waitUntil: "load", timeout: 90000 });
9 +await p.waitForTimeout(8000);
10 +console.log("bad:", bad.slice(0, 15));
11 +console.log("pending:", [...pending.keys()].map((u) => u.slice(0, 140)).slice(0, 15));
12 +await b.close();
added scripts/ws-shot-owner.mjs +13 −0
@@ -0,0 +1,13 @@
1 +import { chromium } from "playwright";
2 +const [,, url, out, w, h, owner] = process.argv;
3 +const b = await chromium.launch();
4 +const ctx = await b.newContext({ viewport: { width: Number(w), height: Number(h) }, colorScheme: "dark", deviceScaleFactor: 1 });
5 +await ctx.addInitScript((o) => { localStorage.setItem("ws_owner", o); if (o.startsWith("ADMIN:")) sessionStorage.setItem("ws_admin", o.slice(6)); }, owner ?? "playwrighttestowner00001");
6 +const p = await ctx.newPage();
7 +p.on("pageerror", (e) => console.log("pageerror:", e.message));
8 +await p.goto(url, { waitUntil: "networkidle", timeout: 90000 });
9 +await p.waitForTimeout(2500);
10 +const overflow = await p.evaluate(() => document.documentElement.scrollWidth > window.innerWidth ? document.documentElement.scrollWidth : 0);
11 +await p.screenshot({ path: out, fullPage: false });
12 +console.log(out, "overflow:", overflow);
13 +await b.close();
added scripts/ws-shot.mjs +12 −0
@@ -0,0 +1,12 @@
1 +import { chromium } from "playwright";
2 +const [,, url, out, w, h, theme] = process.argv;
3 +const b = await chromium.launch();
4 +const ctx = await b.newContext({ viewport: { width: Number(w), height: Number(h) }, colorScheme: theme === "light" ? "light" : "dark", deviceScaleFactor: 1 });
5 +const p = await ctx.newPage();
6 +await p.goto(url, { waitUntil: "networkidle", timeout: 60000 });
7 +if (theme === "light") await p.evaluate(() => { document.documentElement.classList.remove("dark"); localStorage.setItem("theme","light"); });
8 +await p.waitForTimeout(800);
9 +const overflow = await p.evaluate(() => document.documentElement.scrollWidth > window.innerWidth ? document.documentElement.scrollWidth : 0);
10 +await p.screenshot({ path: out, fullPage: false });
11 +console.log(out, "overflow:", overflow);
12 +await b.close();
added scripts/ws-widest.mjs +11 −0
@@ -0,0 +1,11 @@
1 +import { chromium } from "playwright";
2 +const b = await chromium.launch();
3 +const p = await (await b.newContext({ viewport: { width: Number(process.argv[3] ?? 375), height: 812 } })).newPage();
4 +await p.goto(process.argv[2], { waitUntil: "networkidle", timeout: 90000 });
5 +const out = await p.evaluate(() => {
6 + const w = window.innerWidth; const res = [];
7 + for (const el of document.querySelectorAll("body *")) { const r = el.getBoundingClientRect(); if (r.right > w + 2 && r.width < 5000) res.push({ tag: el.tagName, cls: (el.className || "").toString().slice(0, 90), right: Math.round(r.right), text: (el.textContent || "").trim().slice(0, 60) }); }
8 + return res.slice(0, 12);
9 +});
10 +console.log(JSON.stringify(out, null, 1));
11 +await b.close();
added tmp/vp-nav-shot.mjs +7 −0
@@ -0,0 +1,7 @@
1 +import { chromium } from "playwright";
2 +const browser = await chromium.launch();
3 +const ctx = await browser.newContext({ viewport: { width: 1280, height: 400 } });
4 +const page = await ctx.newPage();
5 +await page.goto("https://www.vrai-prix.com/cout", { waitUntil: "networkidle", timeout: 90000 });
6 +await page.screenshot({ path: "/tmp/vp-shots/nav-1280.png", clip: { x: 0, y: 0, width: 1280, height: 60 } });
7 +await browser.close();
added tmp/vp-shots.mjs +26 −0
@@ -0,0 +1,26 @@
1 +import { chromium } from "playwright";
2 +const B = "https://www.vrai-prix.com";
3 +const browser = await chromium.launch();
4 +async function shot(name, url, mobile, full = false, fn) {
5 + const ctx = await browser.newContext(mobile ? { viewport: { width: 390, height: 844 }, deviceScaleFactor: 2, isMobile: true, hasTouch: true } : { viewport: { width: 1440, height: 900 } });
6 + const page = await ctx.newPage();
7 + await page.goto(B + url, { waitUntil: "networkidle", timeout: 90000 });
8 + if (fn) await fn(page);
9 + await page.waitForTimeout(800);
10 + await page.screenshot({ path: `/tmp/vp-shots/${name}.png`, fullPage: full });
11 + await ctx.close();
12 +}
13 +const uid = await (await fetch(B + "/api/avendre?per=1&eval=1&muni=Gatineau&group=maison&sort=recent")).json().then((j) => j.items[0].uid);
14 +console.log("uid", uid);
15 +await shot("home-desktop", "/", false);
16 +await shot("home-mobile", "/", true);
17 +await shot("avendre-desktop", "/a-vendre", false);
18 +await shot("avendre-mobile", "/a-vendre", true);
19 +await shot("fiche-desktop", `/a-vendre/${encodeURIComponent(uid)}`, false);
20 +await shot("fiche-mobile", `/a-vendre/${encodeURIComponent(uid)}`, true);
21 +await shot("evaluer-desktop", `/a-vendre/${encodeURIComponent(uid)}/evaluer`, false);
22 +await shot("cout-desktop", "/cout", false);
23 +await shot("cout-mobile", "/cout", true);
24 +await shot("cout-atelier-desktop", "/cout?property=81017894526868400000000", false, false, (p) => p.waitForTimeout(3000));
25 +await shot("marche-desktop", "/stats/marche", false);
26 +await browser.close();
27