import { test, expect, type Page } from '@playwright/test'; const ADMIN_EMAIL = 'admin@example.com'; const ADMIN_PASSWORD = 'Admin123!'; async function loginAsAdmin(page: Page) { await page.goto('/login'); await page.getByLabel('Email').fill(ADMIN_EMAIL); await page.getByLabel('Password').fill(ADMIN_PASSWORD); await page.getByRole('button', { name: 'Sign In' }).click(); await page.waitForURL('**/dashboard', { timeout: 10000 }); } test.describe('Diagnostics - Debug Sessions', () => { test.beforeEach(async ({ page }) => { await loginAsAdmin(page); }); test('navigates to diagnostics page', async ({ page }) => { await page.click('text=Diagnostics'); await expect(page.getByText('Debug Sessions')).toBeVisible(); await expect(page.getByText('Create Session')).toBeVisible(); }); test('shows session list with filters', async ({ page }) => { await page.click('text=Diagnostics'); // Check filter dropdowns exist await expect(page.getByLabel('Status')).toBeVisible(); await expect(page.getByLabel('Collection Level')).toBeVisible(); // Check table headers await expect(page.getByText('Session ID')).toBeVisible(); await expect(page.getByText('Status')).toBeVisible(); await expect(page.getByText('Target')).toBeVisible(); await expect(page.getByText('Logs')).toBeVisible(); await expect(page.getByText('Traces')).toBeVisible(); await expect(page.getByText('Created')).toBeVisible(); }); test('creates new debug session', async ({ page }) => { await page.click('text=Diagnostics'); await page.click('text=Create Session'); // Should open modal await expect(page.getByText('Create Debug Session')).toBeVisible(); // Fill form await page.getByLabel('Target User ID').fill('user_test_123'); await page.getByLabel('Target Device ID').fill('device_test_456'); // Select collection level await page.getByLabel('Collection Level').selectOption('debug'); // Enable capture options await page.getByLabel('Capture Logs').check(); await page.getByLabel('Capture Network').check(); await page.getByLabel('Capture Screenshots').check(); // Set duration await page.getByLabel('Max Duration (minutes)').fill('30'); // Submit await page.click('text=Start Session'); // Should show success and close modal await expect(page.getByText('Session created')).toBeVisible({ timeout: 5000 }); }); test('views session details', async ({ page }) => { await page.click('text=Diagnostics'); // Click on first session await page.locator('table tbody tr').first().click(); // Should show detail panel await expect(page.getByText('Session Details')).toBeVisible(); await expect(page.getByText('Status')).toBeVisible(); await expect(page.getByText('Collection Level')).toBeVisible(); await expect(page.getByText('Logs')).toBeVisible(); await expect(page.getByText('Traces')).toBeVisible(); await expect(page.getByText('Screenshots')).toBeVisible(); }); test('pauses and resumes session', async ({ page }) => { await page.click('text=Diagnostics'); // Find an active session const activeRow = page.locator('tr:has-text("Active")').first(); if (await activeRow.isVisible().catch(() => false)) { // Click pause await activeRow.getByRole('button', { name: 'Pause' }).click(); await expect(page.getByText('Session paused')).toBeVisible(); // Resume await page .locator('tr:has-text("Paused")') .first() .getByRole('button', { name: 'Resume' }) .click(); await expect(page.getByText('Session resumed')).toBeVisible(); } }); test('cancels session', async ({ page }) => { await page.click('text=Diagnostics'); // Find a pending or active session const sessionRow = page.locator('tr:has-text("Pending"), tr:has-text("Active")').first(); if (await sessionRow.isVisible().catch(() => false)) { await sessionRow.getByRole('button', { name: 'Cancel' }).click(); // Confirm cancel await page.getByLabel('Reason (optional)').fill('Test cancellation'); await page.click('text=Confirm Cancel'); await expect(page.getByText('Session cancelled')).toBeVisible(); } }); test('filters sessions by status', async ({ page }) => { await page.click('text=Diagnostics'); // Filter by Active await page.getByLabel('Status').selectOption('active'); // Should only show active sessions const rows = page.locator('table tbody tr'); const count = await rows.count(); for (let i = 0; i < count; i++) { await expect(rows.nth(i).locator('td').nth(1)).toHaveText('Active'); } }); test('searches sessions by user ID', async ({ page }) => { await page.click('text=Diagnostics'); // Search await page.getByPlaceholder('Search by user/device ID').fill('test_user'); await page.click('text=Search'); // Results should contain search term const firstRow = page.locator('table tbody tr').first(); if (await firstRow.isVisible().catch(() => false)) { await expect(firstRow).toContainText('test_user'); } }); }); test.describe('Diagnostics - Logs & Traces', () => { test.beforeEach(async ({ page }) => { await loginAsAdmin(page); await page.click('text=Diagnostics'); }); test('views session logs', async ({ page }) => { // Click on a session with logs const sessionWithLogs = page.locator('tr:has([data-logs="true"])').first(); if (await sessionWithLogs.isVisible().catch(() => false)) { await sessionWithLogs.click(); // Click Logs tab await page.click('text=Logs'); // Should show log entries await expect(page.locator('[data-testid="log-entry"]').first()).toBeVisible(); // Check log level badges await expect( page.getByText('INFO').or(page.getByText('ERROR')).or(page.getByText('DEBUG')) ).toBeVisible(); } }); test('filters logs by level', async ({ page }) => { // Open a session and go to logs const sessionWithLogs = page.locator('tr:has([data-logs="true"])').first(); if (await sessionWithLogs.isVisible().catch(() => false)) { await sessionWithLogs.click(); await page.click('text=Logs'); // Filter by ERROR await page.getByLabel('Log Level').selectOption('error'); // All visible logs should be ERROR level const logs = page.locator('[data-testid="log-entry"]'); const count = await logs.count(); for (let i = 0; i < count; i++) { await expect(logs.nth(i).locator('[data-level]')).toHaveAttribute('data-level', 'error'); } } }); test('searches logs by message', async ({ page }) => { const sessionWithLogs = page.locator('tr:has([data-logs="true"])').first(); if (await sessionWithLogs.isVisible().catch(() => false)) { await sessionWithLogs.click(); await page.click('text=Logs'); // Search await page.getByPlaceholder('Search logs...').fill('error'); await page.click('text=Search'); // Results should contain search term const firstLog = page.locator('[data-testid="log-entry"]').first(); if (await firstLog.isVisible().catch(() => false)) { await expect(firstLog).toContainText('error'); } } }); test('views trace spans', async ({ page }) => { const sessionWithTraces = page.locator('tr:has([data-traces="true"])').first(); if (await sessionWithTraces.isVisible().catch(() => false)) { await sessionWithTraces.click(); await page.click('text=Traces'); // Should show trace tree await expect(page.locator('[data-testid="trace-span"]').first()).toBeVisible(); // Should show span details await expect(page.getByText('Duration')).toBeVisible(); await expect(page.getByText('Status')).toBeVisible(); } }); test('expands trace span details', async ({ page }) => { const sessionWithTraces = page.locator('tr:has([data-traces="true"])').first(); if (await sessionWithTraces.isVisible().catch(() => false)) { await sessionWithTraces.click(); await page.click('text=Traces'); // Click to expand first span const firstSpan = page.locator('[data-testid="trace-span"]').first(); await firstSpan.click(); // Should show span details await expect(page.getByText('Attributes')).toBeVisible(); await expect(page.getByText('Events')).toBeVisible(); } }); }); test.describe('Diagnostics - Screenshots', () => { test.beforeEach(async ({ page }) => { await loginAsAdmin(page); await page.click('text=Diagnostics'); }); test('views screenshots gallery', async ({ page }) => { const sessionWithScreenshots = page.locator('tr:has([data-screenshots="true"])').first(); if (await sessionWithScreenshots.isVisible().catch(() => false)) { await sessionWithScreenshots.click(); await page.click('text=Screenshots'); // Should show screenshot thumbnails await expect(page.locator('[data-testid="screenshot-thumb"]').first()).toBeVisible(); } }); test('opens screenshot lightbox', async ({ page }) => { const sessionWithScreenshots = page.locator('tr:has([data-screenshots="true"])').first(); if (await sessionWithScreenshots.isVisible().catch(() => false)) { await sessionWithScreenshots.click(); await page.click('text=Screenshots'); // Click first screenshot await page.locator('[data-testid="screenshot-thumb"]').first().click(); // Lightbox should open await expect(page.locator('[data-testid="screenshot-lightbox"]')).toBeVisible(); await expect(page.locator('[data-testid="screenshot-full"]').first()).toBeVisible(); } }); test('navigates between screenshots', async ({ page }) => { const sessionWithScreenshots = page.locator('tr:has([data-screenshots="true"])').first(); if (await sessionWithScreenshots.isVisible().catch(() => false)) { await sessionWithScreenshots.click(); await page.click('text=Screenshots'); // Open lightbox await page.locator('[data-testid="screenshot-thumb"]').first().click(); // Navigate next await page.click('text=Next'); await expect(page.getByText('2 /')).toBeVisible(); // Navigate prev await page.click('text=Previous'); await expect(page.getByText('1 /')).toBeVisible(); } }); }); test.describe('Diagnostics - End-to-End Flow', () => { test.beforeEach(async ({ page }) => { await loginAsAdmin(page); }); test('full workflow: create → capture → analyze', async ({ page }) => { // 1. Create session await page.click('text=Diagnostics'); await page.click('text=Create Session'); const targetUserId = `test_user_${Date.now()}`; await page.getByLabel('Target User ID').fill(targetUserId); await page.getByLabel('Collection Level').selectOption('debug'); await page.getByLabel('Capture Logs').check(); await page.click('text=Start Session'); await expect(page.getByText('Session created')).toBeVisible(); // 2. Verify session appears in list await expect(page.locator('table tbody tr').first()).toContainText(targetUserId); // 3. Open session details await page.locator(`tr:has-text("${targetUserId}")`).first().click(); await expect(page.getByText('Session Details')).toBeVisible(); // 4. View logs (if any captured) await page.click('text=Logs'); // 5. Pause session await page.click('text=Actions'); await page.click('text=Pause'); await expect(page.getByText('Session paused')).toBeVisible(); // 6. Resume and complete await page.click('text=Actions'); await page.click('text=Resume'); await page.click('text=Actions'); await page.click('text=Complete'); await expect(page.getByText('Session completed')).toBeVisible(); }); test('error threshold triggers auto-notification', async ({ page }) => { // This would require backend simulation of error threshold // For E2E, we verify the UI handles the notification await page.click('text=Diagnostics'); // Look for notification about high error rate const notification = page.locator('[data-testid="error-threshold-alert"]'); if (await notification.isVisible().catch(() => false)) { await expect(notification).toContainText('High error rate detected'); // Should offer to create debug session await notification.getByRole('button', { name: 'Start Debug Session' }).click(); await expect(page.getByText('Create Debug Session')).toBeVisible(); } }); test('crash-triggered auto-session', async ({ page }) => { // Look for auto-created session after crash await page.click('text=Diagnostics'); // Filter to show auto-created sessions await page.getByLabel('Source').selectOption('auto_crash'); // Should show auto-created sessions const autoSession = page.locator('tr:has-text("Auto-created")').first(); if (await autoSession.isVisible().catch(() => false)) { await expect(autoSession).toContainText('Crash detected'); // Open and verify it has crash data await autoSession.click(); await page.click('text=Logs'); await expect(page.locator('[data-testid="log-entry"]')).toContainText('CRASH'); } }); });