import { chromium } from 'playwright'; import { APP_URL, AUTH_STATE_PATH, DASHBOARD_PATH } from './config.js'; import { viewportFor } from './script.js'; import { storyboards } from './storyboard.js'; async function main() { // probe is a debug utility — pin it to the first storyboard's viewport. const viewport = viewportFor(storyboards[0].video); const browser = await chromium.launch({ headless: true }); const context = await browser.newContext({ storageState: AUTH_STATE_PATH, viewport, }); const page = await context.newPage(); page.on('request', (r) => { if (r.url().includes('auth-refresh')) { console.log('REQ', r.method(), r.url(), 'headers:', JSON.stringify(r.headers())); } }); page.on('response', async (r) => { if (r.url().includes('auth-refresh')) { const body = await r.text().catch(() => ''); console.log('RES', r.status(), r.url(), 'body:', body.slice(0, 200)); } }); await page.goto(`${APP_URL}${DASHBOARD_PATH}`, { waitUntil: 'networkidle' }); await new Promise((r) => setTimeout(r, 1500)); await page.screenshot({ path: 'output/probe-1-initial.png', fullPage: false }); const ls = await page.evaluate(() => { const v = localStorage.getItem('pocketbase_auth'); let parsed: unknown = null; try { parsed = v ? JSON.parse(v) : null; } catch {} return { raw: v?.slice(0, 80), hasToken: !!(parsed as { token?: string })?.token, hasRecord: !!(parsed as { record?: unknown })?.record, hasModel: !!(parsed as { model?: unknown })?.model, }; }); console.log('pb_auth localStorage:', ls); const refreshTest = await page.evaluate(async () => { const stored = JSON.parse(localStorage.getItem('pb_auth') ?? '{}'); const r = await fetch('/pb/api/collections/users/auth-refresh', { method: 'POST', headers: { Authorization: stored.token }, }); return { status: r.status, body: (await r.text()).slice(0, 200) }; }); console.log('refresh test:', refreshTest); // Try the SDK path directly. Reach into the Vite-served module graph. const sdkRefresh = await page.evaluate(async () => { type W = Window & { pb?: { collection: (n: string) => { authRefresh: () => Promise }, authStore: { isValid: boolean, token: string, record: unknown } } }; const w = window as W; if (!w.pb) return { error: 'window.pb not exposed' }; const before = { isValid: w.pb.authStore.isValid, hasToken: !!w.pb.authStore.token }; try { const out = await w.pb.collection('users').authRefresh(); return { before, ok: true, out }; } catch (e) { return { before, ok: false, error: String(e) }; } }); console.log('SDK refresh:', sdkRefresh); const aiCount = await page.locator('[data-tutorial="ai-filters"]').count(); const aiVisible = await page.locator('[data-tutorial="ai-filters"]').first().isVisible().catch(() => false); const aiBtnCount = await page.locator('[data-tutorial="ai-filters"] button').count(); const filterCount = await page.locator('[data-filter-name]').count(); const filterNames = await page.locator('[data-filter-name]').evaluateAll((els) => els.map((e) => e.getAttribute('data-filter-name')) ); const tutorialOverlay = await page.locator('[role="dialog"], [data-tutorial-step], .tutorial-overlay').count(); console.log({ aiCount, aiVisible, aiBtnCount, filterCount, filterNames, tutorialOverlay }); // Try clicking the AI button and check whether textarea appears const aiBtn = page.locator('[data-tutorial="ai-filters"] button').first(); if (await aiBtn.isVisible()) { await aiBtn.click(); await new Promise((r) => setTimeout(r, 600)); const taCount = await page.locator('[data-tutorial="ai-filters"] textarea').count(); console.log({ afterClick_taCount: taCount }); await page.screenshot({ path: 'output/probe-2-after-click.png' }); } await browser.close(); } main().catch((e) => { console.error(e); process.exit(1); });