/** * IndexedDB injection helpers for Playwright tests. * * These functions execute inside the browser via page.evaluate() — they must be * self-contained and cannot close over test-scope variables (only the single * argument passed to page.evaluate is available). * * Standard pattern for using inject_badge_and_template: * * await page.goto('/events/{event_id}/badges/{badge_id}/print'); * await page.waitForLoadState('domcontentloaded'); * await page.evaluate(inject_badge_and_template, { badge, template }); * await page.reload(); * await page.waitForLoadState('domcontentloaded'); * * Why reload after injection: direct IDB writes bypass Dexie's internal * change-notification system, so liveQuery subscribers don't re-fire. * Reloading starts the page fresh against the already-populated IDB. */ /** Injects a badge and badge_template record into ae_events_db. */ export async function inject_badge_and_template( { badge, template }: { badge: object; template: object } ): Promise { // Wait for Dexie to have fully initialised ae_events_db with its stores. // domcontentloaded fires before Dexie's version migration runs, so the DB // may not have the 'badge' / 'badge_template' stores yet when we arrive here. await new Promise((resolve, reject) => { const poll = () => { const req = indexedDB.open('ae_events_db'); req.onsuccess = () => { const db = req.result as IDBDatabase; const ready = db.objectStoreNames.contains('badge') && db.objectStoreNames.contains('badge_template'); db.close(); if (ready) resolve(); else setTimeout(poll, 100); }; req.onerror = () => reject((req as IDBRequest).error); }; poll(); }); const db = await new Promise((resolve, reject) => { const req = indexedDB.open('ae_events_db'); req.onsuccess = () => resolve(req.result as IDBDatabase); req.onerror = () => reject((req as IDBRequest).error); }); await new Promise((resolve, reject) => { const tx = db.transaction(['badge', 'badge_template'], 'readwrite'); tx.objectStore('badge').put(badge); tx.objectStore('badge_template').put(template); tx.oncomplete = () => { db.close(); resolve(); }; tx.onerror = () => { db.close(); reject(tx.error); }; }); }