import { test, expect } from '@playwright/test'; import { ae_app_local_data_defaults } from './_helpers/ae_defaults'; import { testing_event_id, testing_account_id } from './_helpers/env'; // Demo test data IDs from One Sky IT Demo environment // Session: (703) "How To Do Things" // Presentation: (1670) "Build a House" // Presenter: (2202) "Bob The Builder" const event_session_id = 'DOW3h7v6H42'; // Per README test data const event_presentation_id = '7U2eXSjR6H4'; // Per README test data const event_presenter_id = 'gT-hxnifb-0'; // Per README test data test.describe('Cold-start: Event Session (IndexedDB empty)', () => { test.beforeEach(async ({ page }) => { page.on('pageerror', (err) => console.error(`BROWSER ERROR: ${err.message}`)); page.on('console', (msg) => { if (msg.type() === 'error' || msg.type() === 'warning') console.error(`BROWSER [${msg.type().toUpperCase()}]: ${msg.text()}`); }); // Provide app localStorage before any scripts run await page.addInitScript( ({ defaults, event_id, account_id }) => { const test_data = { ...defaults, account_id: account_id, administrator_access: true, trusted_access: true, authenticated_access: true, manager_access: false, super_access: false, edit_mode: true, mod_abstracts_json: {}, person_id: 'QWODAPCNLQU', // Per README test data user: { id: 'QWODAPCNLQU' }, // Per README test data mod: { ...defaults.mod, events: { ...defaults.mod.events, event_id: event_id } } }; window.localStorage.setItem('ae_loc', JSON.stringify(test_data)); }, { defaults: ae_app_local_data_defaults, event_id: testing_event_id, account_id: testing_account_id } ); // Navigate to the application's origin so the page context is allowed // to access the IndexedDB API, then delete known Dexie DBs to simulate // a cold start. await page.goto('/'); await page.evaluate(() => { const dbs = [ 'ae_events_db', 'ae_journals_db', 'ae_posts_db', 'ae_archives_db', 'ae_core_db', 'ae_sponsorships_db' ]; return Promise.all( dbs.map((name) => new Promise((resolve) => { try { const req = indexedDB.deleteDatabase(name); req.onsuccess = () => resolve(true); req.onerror = () => resolve(false); req.onblocked = () => resolve(false); } catch (e) { resolve(false); } }) ) ); }); // Network mock: minimal responses for session, presentations, presenters await page.route('**/v3/crud/**', async (route) => { const req = route.request(); const url = req.url(); const method = req.method(); // Session GET if (url.includes(`/v3/crud/event_session/${event_session_id}`) && method === 'GET') { return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: { id: event_session_id, event_session_id: event_session_id, event_id: testing_event_id, name: 'How To Do Things', code: 'how-to-do-things', start_datetime: '2026-03-01T10:00:00Z', end_datetime: '2026-03-01T11:00:00Z', description: 'Cold start test session', event_location_id: 'VXXY-98-46-14', // Per README test data poc_person_id: 'QWODAPCNLQU', // Per README test data cfg_json: {}, mod_pres_mgmt_json: {} } }) }); } // Presentations list for session if (url.includes('/v3/crud/event_presentation') && url.includes('for_obj_id') && url.includes(event_session_id) && method === 'GET') { return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [ { id: event_presentation_id, event_presentation_id: event_presentation_id, event_session_id: event_session_id, event_id: testing_event_id, name: 'Build a House', code: 'build-house', start_datetime: '2026-03-01T10:00:00Z', end_datetime: '2026-03-01T10:30:00Z' } ] }) }); } // Presenters for "Build a House" presentation if (url.includes('/v3/crud/event_presenter') && url.includes(`for_obj_id=${event_presentation_id}`) && method === 'GET') { return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [ { id: event_presenter_id, event_presenter_id: event_presenter_id, event_presentation_id: event_presentation_id, event_session_id: event_session_id, event_id: testing_event_id, given_name: 'Bob', family_name: 'The Builder', full_name: 'Bob The Builder', email: 'bob@builder.example.com' } ] }) }); } // Default: empty envelope return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [] }) }); }); }); test('renders Session with Presentations and Presenters on first load', async ({ page }) => { // Navigate directly to the session page (cold start - no IDB data) await page.goto(`/events/${testing_event_id}/session/${event_session_id}`); // 1. Verify session name is visible await expect(page.getByText('How To Do Things')).toBeVisible({ timeout: 10000 }); // 2. Verify presentation is visible await expect(page.getByText('Build a House')).toBeVisible({ timeout: 5000 }); // 3. CRITICAL: Verify presenter is visible WITHOUT manual refresh // This is the bug we're fixing - presenters should appear on first load await expect(page.getByText('Bob The Builder')).toBeVisible({ timeout: 10000 }); // 4. Verify the presentations count display const presCountBadge = page.locator('text=/Presentations:/').locator('..').getByText('1'); await expect(presCountBadge).toBeVisible({ timeout: 5000 }); }); test('verifies IndexedDB contains all nested data after load', async ({ page }) => { await page.goto(`/events/${testing_event_id}/session/${event_session_id}`); // Wait for data to be visible (indicating IDB writes completed) await expect(page.getByText('Bob The Builder')).toBeVisible({ timeout: 10000 }); // Inspect IndexedDB to verify data integrity const idbData = await page.evaluate(async () => { const openDB = (name: string) => new Promise((resolve, reject) => { const req = indexedDB.open(name); req.onsuccess = () => resolve(req.result); req.onerror = () => reject(req.error); }); const getAllFromStore = (db: IDBDatabase, storeName: string) => new Promise((resolve) => { const tx = db.transaction(storeName, 'readonly'); const store = tx.objectStore(storeName); const req = store.getAll(); req.onsuccess = () => resolve(req.result); req.onerror = () => resolve([]); }); try { const db = await openDB('ae_events_db'); const sessions = await getAllFromStore(db, 'session'); const presentations = await getAllFromStore(db, 'presentation'); const presenters = await getAllFromStore(db, 'presenter'); db.close(); return { sessions, presentations, presenters }; } catch (e) { return { sessions: [], presentations: [], presenters: [], error: String(e) }; } }); // Verify data was written to IDB expect(idbData.sessions.length).toBeGreaterThan(0); expect(idbData.presentations.length).toBe(1); expect(idbData.presenters.length).toBe(1); // Verify presenter name is in IDB const presenterNames = idbData.presenters.map((p: any) => p.full_name); expect(presenterNames).toContain('Bob The Builder'); }); });