← back to Visual Factory
scripts/clickthrough.js
88 lines
// Live click-through of the Visual Factory viewer.
// Opens :9893, screenshots the gallery, clicks each row's modal, screenshots that.
const { chromium } = require('playwright');
const path = require('node:path');
const fs = require('node:fs/promises');
const VIEWER = 'http://127.0.0.1:9893';
const ORCH = 'http://127.0.0.1:9892';
const OUT = path.join(__dirname, '..', 'output', 'clickthrough');
(async () => {
await fs.mkdir(OUT, { recursive: true });
const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 2 });
const page = await ctx.newPage();
const consoleMsgs = [];
page.on('console', m => consoleMsgs.push(`[${m.type()}] ${m.text()}`));
page.on('pageerror', e => consoleMsgs.push(`[PAGEERROR] ${e.message}`));
console.log('STEP 1: gallery');
await page.goto(VIEWER, { waitUntil: 'networkidle', timeout: 15000 });
// Give the JS poll a moment to load runs from the orch
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(OUT, '01-gallery.png'), fullPage: true });
// How many cards rendered?
const cardCount = await page.locator('.card').count();
console.log(` cards rendered: ${cardCount}`);
// Activate buttons present?
const activateCount = await page.locator('.activate-btn').count();
console.log(` activate buttons: ${activateCount}`);
// STEP 2: click first card → modal
console.log('STEP 2: click first card');
if (cardCount > 0) {
// Click the card body (not the activate button). We click the .meta div to avoid stopPropagation issues.
await page.locator('.card').first().locator('.meta').click();
await page.waitForSelector('.modal-bg.open', { timeout: 5000 });
await page.waitForTimeout(800);
await page.screenshot({ path: path.join(OUT, '02-modal-first.png'), fullPage: false });
// Close the modal by clicking outside
await page.locator('.modal-bg').click({ position: { x: 10, y: 10 } });
await page.waitForTimeout(400);
}
// STEP 3: click third card (different visual_type)
console.log('STEP 3: click third card');
if (cardCount > 2) {
await page.locator('.card').nth(2).locator('.meta').click();
await page.waitForSelector('.modal-bg.open', { timeout: 5000 });
await page.waitForTimeout(800);
await page.screenshot({ path: path.join(OUT, '03-modal-third.png'), fullPage: false });
await page.locator('.modal-bg').click({ position: { x: 10, y: 10 } });
await page.waitForTimeout(400);
}
// STEP 4: click fifth card
console.log('STEP 4: click fifth card');
if (cardCount > 4) {
await page.locator('.card').nth(4).locator('.meta').click();
await page.waitForSelector('.modal-bg.open', { timeout: 5000 });
await page.waitForTimeout(800);
await page.screenshot({ path: path.join(OUT, '04-modal-fifth.png'), fullPage: false });
}
// Diagnostics
await fs.writeFile(path.join(OUT, 'console.log'), consoleMsgs.join('\n'), 'utf8');
const summary = {
viewer_status: 'reachable',
cards_rendered: cardCount,
activate_buttons: activateCount,
console_messages: consoleMsgs.length,
screenshots: ['01-gallery.png', '02-modal-first.png', '03-modal-third.png', '04-modal-fifth.png']
};
await fs.writeFile(path.join(OUT, 'summary.json'), JSON.stringify(summary, null, 2));
console.log('SUMMARY:', JSON.stringify(summary));
// Also probe orchestrator endpoints
const health = await (await fetch(`${ORCH}/health`)).json();
const runs = await (await fetch(`${ORCH}/runs`)).json();
console.log(`ORCH /health: ${JSON.stringify(health)}`);
console.log(`ORCH /runs: ${runs.runs?.length || 0} runs`);
await browser.close();
})().catch(e => { console.error(e); process.exit(1); });