Files
EventSnap/e2e/loadtest/diashow-watch.mjs
MechaCat02 9b8698f86b test(loadtest): 100-guest / 1000-image stress harness
HTTP-level load driver simulating ~100 guests uploading ~1000 images in bursts
over a window, plus SSE viewers and one real browser on /diashow. Correlates
upload→upload-processed (pipeline latency), waits for the compression backlog
to drain against DB ground truth, and emits per-status/latency metrics with
pass/fail flags. Includes a realistic-JPEG generator and a diashow-SSE
regression check (confirm-diashow-fix.mjs). Run artifacts are gitignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 17:29:20 +02:00

106 lines
4.0 KiB
JavaScript

#!/usr/bin/env node
/**
* The showcase display. Opens ONE real Chromium browser on /diashow (as a
* logged-in guest) for the duration of a load run, so we validate the real
* SSE → render path a projector/TV would use — not just the protocol.
*
* Run it alongside driver.mjs (separate terminal), started first:
* node diashow-watch.mjs
* # then in another terminal:
* node driver.mjs
*
* It captures:
* - periodic screenshots (so you can eyeball that new photos actually appear)
* - browser console errors / page crashes / SSE disconnects surfaced in console
* - a final count of slides rendered
*
* Env:
* LT_BASE http://localhost:3101
* LT_WATCH_SEC 960 how long to keep the display open
* LT_SHOT_EVERY_SEC 30 screenshot cadence
* LT_OUT_DIR ./results/diashow
*/
import { chromium, devices } from '@playwright/test';
import { mkdirSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __dirname = dirname(fileURLToPath(import.meta.url));
const BASE = process.env.LT_BASE ?? 'http://localhost:3101';
const WATCH_SEC = parseInt(process.env.LT_WATCH_SEC ?? '960', 10);
const SHOT_EVERY = parseInt(process.env.LT_SHOT_EVERY_SEC ?? '30', 10);
const OUT = process.env.LT_OUT_DIR ?? join(__dirname, 'results', 'diashow');
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function joinGuest(name) {
const res = await fetch(`${BASE}/api/v1/join`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ display_name: name }),
});
if (res.status !== 201) throw new Error(`join failed ${res.status}`);
return res.json();
}
async function main() {
mkdirSync(OUT, { recursive: true });
const guest = await joinGuest('Showcase Display');
console.log('[diashow] joined showcase guest, launching browser…');
const browser = await chromium.launch();
// A TV/projector is landscape; use a desktop-ish large viewport.
const ctx = await browser.newContext({ viewport: { width: 1920, height: 1080 } });
const page = await ctx.newPage();
let consoleErrors = 0;
page.on('console', (msg) => {
if (msg.type() === 'error') {
consoleErrors++;
console.log('[diashow][console.error]', msg.text().slice(0, 200));
}
});
page.on('pageerror', (e) => console.log('[diashow][pageerror]', String(e).slice(0, 200)));
page.on('crash', () => console.log('[diashow][CRASH] page crashed'));
// Seed auth in localStorage on the origin, then open /diashow.
await page.goto(`${BASE}/join`, { waitUntil: 'domcontentloaded' });
await page.evaluate((g) => {
localStorage.setItem('eventsnap_theme', 'dark');
localStorage.setItem('eventsnap_jwt', g.jwt);
localStorage.setItem('eventsnap_pin', g.pin);
localStorage.setItem('eventsnap_user_id', g.user_id);
localStorage.setItem('eventsnap_display_name', 'Showcase Display');
localStorage.setItem('eventsnap_guide_seen', '1');
}, guest);
await page.goto(`${BASE}/diashow`, { waitUntil: 'domcontentloaded' });
console.log(`[diashow] on /diashow, watching for ${WATCH_SEC}s (shots every ${SHOT_EVERY}s)`);
const start = Date.now();
let shot = 0;
while ((Date.now() - start) / 1000 < WATCH_SEC) {
await sleep(SHOT_EVERY * 1000);
const elapsed = Math.round((Date.now() - start) / 1000);
// best-effort slide count (diashow renders <img>; adjust selector if markup changes)
let imgs = -1;
try {
imgs = await page.locator('img').count();
} catch {
/* ignore */
}
const path = join(OUT, `diashow-t${String(elapsed).padStart(4, '0')}.png`);
await page.screenshot({ path }).catch(() => {});
console.log(`[diashow][t+${elapsed}s] imgs≈${imgs} consoleErrors=${consoleErrors}${path}`);
shot++;
}
console.log(`[diashow] done. ${shot} screenshots, ${consoleErrors} console errors total.`);
await browser.close();
}
main().catch((e) => {
console.error('[diashow] failed:', e);
process.exit(1);
});