WIP laptop non committé (17 fichiers), sauvegardé lors de la réorganisation du 2026-10-02
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 | ||