import puppeteer from 'puppeteer'; const BASE = 'http://localhost:5173'; const OUT = process.env.HOME + '/Desktop/proposal-system-screenshots'; const ROLES = [ { label: 'SysAdmin', prefix: 'sysadmin', isAdmin: true, isSysAdmin: true }, { label: 'Admin', prefix: 'admin', isAdmin: true, isSysAdmin: false }, { label: 'Dispatcher', prefix: 'dispatcher', isAdmin: false, isSysAdmin: false }, ]; async function wait(ms) { return new Promise(r => setTimeout(r, ms)); } async function screenshot(page, name) { await wait(1500); await page.screenshot({ path: `${OUT}/${name}.png`, fullPage: true }); console.log(` captured ${name}.png`); } async function getToken(page) { return page.evaluate(() => { const raw = localStorage.getItem('proposal_system_token'); if (!raw) return null; try { const parsed = JSON.parse(raw); return parsed?.token ?? null; } catch { return null; } }); } async function fetchProposalId(page) { const token = await getToken(page); if (!token) return null; return page.evaluate(async (t) => { try { const r = await fetch('/api/proposals?page=1&pageSize=1', { headers: { 'Authorization': `Bearer ${t}` }, }); if (!r.ok) return null; const data = await r.json(); return data.items?.[0]?.id ?? null; } catch { return null; } }, token); } async function run() { const browser = await puppeteer.launch({ headless: true, defaultViewport: { width: 1440, height: 900 }, }); for (const role of ROLES) { console.log(`\n--- ${role.prefix} ---`); const context = await browser.createBrowserContext(); const page = await context.newPage(); // Login page await page.goto(BASE + '/login', { waitUntil: 'networkidle2' }); await screenshot(page, `${role.prefix}-01-login`); // Click the role button const buttons = await page.$$('button'); let clicked = false; for (const b of buttons) { const text = await b.evaluate(el => el.textContent.trim()); if (text.startsWith(role.label)) { await b.click(); clicked = true; break; } } if (!clicked) { console.log(` ERROR: could not find button "${role.label}"`); await context.close(); continue; } await page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 10000 }).catch(() => {}); await wait(1000); // Dashboard await screenshot(page, `${role.prefix}-02-dashboard`); // My Proposals list await page.goto(BASE + '/proposals', { waitUntil: 'networkidle2' }); await screenshot(page, `${role.prefix}-03-proposals-list`); // New Proposal form await page.goto(BASE + '/proposals/new', { waitUntil: 'networkidle2' }); await screenshot(page, `${role.prefix}-04-new-proposal`); // Detail page const proposalId = await fetchProposalId(page); if (proposalId) { await page.goto(BASE + `/proposals/${proposalId}`, { waitUntil: 'networkidle2' }); await screenshot(page, `${role.prefix}-05-proposal-detail`); } else { console.log(' no proposals found, skipping detail'); } if (role.isAdmin) { await page.goto(BASE + '/admin', { waitUntil: 'networkidle2' }); await screenshot(page, `${role.prefix}-06-admin-queue`); await page.goto(BASE + '/admin/proposals', { waitUntil: 'networkidle2' }); await screenshot(page, `${role.prefix}-07-admin-all-proposals`); const workspaceId = proposalId ?? await fetchProposalId(page); if (workspaceId) { await page.goto(BASE + `/admin/proposals/${workspaceId}`, { waitUntil: 'networkidle2' }); await wait(2000); await screenshot(page, `${role.prefix}-08-admin-workspace`); } else { console.log(' no proposals for workspace'); } if (role.isSysAdmin) { await page.goto(BASE + '/admin/users', { waitUntil: 'networkidle2' }); await screenshot(page, `${role.prefix}-09-user-management`); } } await context.close(); } await browser.close(); console.log(`\nDone — screenshots in ${OUT}`); } run().catch(e => { console.error(e); process.exit(1); });