← back to Marketing Command Center
scripts/screenrecord-posts.js
93 lines
// /screenrecord harness v2 — nav by REAL label text (nav <a>s have no href/data-panel).
const { chromium } = require('playwright');
const fs = require('fs');
const path = require('path');
const BASE = 'https://marketing.designerwallcoverings.com';
const CREDS = { username: 'admin', password: 'DW2024!' };
const ROOT = path.join(__dirname, '..', 'screenrecord');
const LOG = path.join(ROOT, 'debug-log.jsonl');
fs.mkdirSync(path.join(ROOT, 'rec'), { recursive: true });
const append = o => fs.appendFileSync(LOG, JSON.stringify(o) + '\n');
// label text (regex-safe fragment) → short id
const PANELS = [
['Streams Board', 'board'],
['Social Scheduler', 'social'],
['Engine', 'engine'],
['Composer', 'composer'],
['Campaign Templates', 'templates'],
['Suggested Copy', 'copy'],
['Marketing Calendar', 'calendar'],
];
const prior = fs.existsSync(LOG) ? fs.readFileSync(LOG, 'utf8').trim().split('\n').filter(Boolean).map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean) : [];
const priorBad = new Set(prior.filter(r => r.errors && r.errors.length).map(r => r.id));
function orderFor(run, els) {
if (run === 0) return els;
if (run === 1) return [...els].reverse();
if (run === 2) return [...els].sort((a, b) => (b[1] === 'engine') - (a[1] === 'engine'));
if (run === 3) { const s = [...els]; for (let i = s.length - 1; i > 0; i--) { const j = (i * 7 + run * 13) % (i + 1); [s[i], s[j]] = [s[j], s[i]]; } return s; }
return [...els].sort((a, b) => priorBad.has(b[1]) - priorBad.has(a[1]));
}
async function inspectCards(page) {
return await page.evaluate(() => {
const sels = ['.bd-card', '.card', '[class*="card"]', '.post', '[class*="post"]', '.engine-card', '.sched-card', 'article'];
const seen = new Set(); const cards = [];
for (const s of sels) for (const el of document.querySelectorAll(s)) {
if (seen.has(el)) continue; seen.add(el);
const r = el.getBoundingClientRect();
if (r.width < 40 || r.height < 20) continue;
cards.push(el);
}
let blank = 0, withText = 0, withImg = 0, brokenImg = 0;
const samples = [];
for (const el of cards) {
const txt = (el.innerText || '').trim();
const imgs = [...el.querySelectorAll('img')];
const loaded = imgs.filter(i => i.complete && i.naturalWidth > 0);
const broken = imgs.filter(i => i.complete && i.naturalWidth === 0 && i.getAttribute('src'));
if (txt.length < 2 && loaded.length === 0) blank++;
if (txt.length >= 2) withText++;
if (loaded.length) withImg++;
brokenImg += broken.length;
if (samples.length < 3 && (txt.length < 2 || broken.length)) samples.push({ textLen: txt.length, imgs: imgs.length, loaded: loaded.length, broken: broken.length, brokenSrc: (broken[0] && broken[0].getAttribute('src') || '').slice(0, 90), cls: el.className.slice(0, 40) });
}
const title = (document.querySelector('.panel-title, h1, h2')?.innerText || '').trim().slice(0, 50);
return { title, total: cards.length, blank, withText, withImg, brokenImg, samples };
});
}
(async () => {
for (let run = 0; run < 5; run++) {
const browser = await chromium.launch();
const ctx = await browser.newContext({ viewport: { width: 1600, height: 900 }, httpCredentials: CREDS, recordVideo: { dir: path.join(ROOT, 'rec', `run${run}`) } });
const page = await ctx.newPage();
const errs = [], api = [], bad = [];
page.on('console', m => { if (m.type() === 'error') errs.push(m.text().slice(0, 200)); });
page.on('pageerror', e => errs.push(('PAGEERROR ' + e).slice(0, 200)));
page.on('response', async r => {
const u = r.url();
if (r.status() >= 400) bad.push(r.status() + ' ' + u.replace(BASE, '').slice(0, 110));
if (/\/api\//.test(u)) { let len = -1; try { len = (await r.body()).length; } catch {} api.push({ url: u.replace(BASE, ''), status: r.status(), len }); }
});
await page.goto(BASE + '/', { waitUntil: 'domcontentloaded' });
await page.waitForTimeout(2500);
for (const [label, id] of orderFor(run, PANELS)) {
errs.length = 0; api.length = 0; bad.length = 0;
let clicked = false;
try {
const el = page.locator('a', { hasText: new RegExp(label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i') }).first();
if (await el.count()) { await el.click({ timeout: 4000 }); clicked = true; }
} catch {}
await page.waitForTimeout(2800);
let cards = null; try { cards = await inspectCards(page); } catch (e) { cards = { err: '' + e }; }
append({ run, id, label, clicked, title: cards.title, cards, api: api.slice(0, 10), bad: [...new Set(bad)].slice(0, 8), errors: [...new Set(errs)].slice(0, 6) });
console.log(`run${run} ${id.padEnd(9)} title="${cards.title}" clicked=${clicked} cards=${cards.total} blank=${cards.blank} text=${cards.withText} img=${cards.withImg} broken=${cards.brokenImg} 4xx=${[...new Set(bad)].length} err=${[...new Set(errs)].length}`);
}
await ctx.close(); await browser.close();
}
console.log('DONE →', LOG);
})().catch(e => { console.error('FATAL', e); process.exit(1); });