import { test, expect } from '@playwright/test'; import { login, BASE_URL } from '../../helpers/auth'; import { markPartial } from '../../helpers/manual'; test.describe('pbx-logs', () => { test.beforeEach(async ({ page }) => { await login(page); }); test('pbx-logs-check-cdr_generation_accuracy_completeness_and_export', async ({ page }, testInfo) => { testInfo.annotations.push({ type: 'automationStatus', description: 'automated' }); testInfo.annotations.push({ type: 'testType', description: 'check' }); testInfo.annotations.push({ type: 'description', description: 'Verify CDR records are generated, contain all required fields, and can be exported to CSV/PDF' }); await test.step('Navigate to Reports → CDR', async () => { await page.goto(`${BASE_URL}/admin/logs/cdr`); }); await test.step('Verify CDR page loads without errors', async () => { await expect(page.locator('body')).not.toContainText(/500|not found/i); }); await test.step('Verify CDR table is visible', async () => { await expect(page.locator('table, .cdr-list, .report-table').first()).toBeVisible(); }); await test.step('Verify required CDR columns are present (start time, duration, from, to, status)', async () => { const headerText = await page.locator('thead, .table-header').first().textContent() ?? ''; const requiredCols = ['time', 'duration', 'from', 'to', 'status']; for (const col of requiredCols) { expect(headerText.toLowerCase()).toContain(col); } }); await test.step('Trigger CSV export and verify download', async () => { const [download] = await Promise.all([ page.waitForEvent('download', { timeout: 20_000 }), page.locator('button:has-text("Export"),a:has-text("CSV"),a:has-text("Download")').first().click(), ]); expect(download.suggestedFilename()).toMatch(/\.(csv|xlsx|pdf)$/i); }); }); test('pbx-logs-check-real_time_active_call_and_registration_monitoring', async ({ page }, testInfo) => { testInfo.annotations.push({ type: 'automationStatus', description: 'automated' }); testInfo.annotations.push({ type: 'testType', description: 'check' }); testInfo.annotations.push({ type: 'description', description: 'Verify real-time monitoring dashboard shows active calls and SIP registrations with auto-refresh' }); await test.step('Navigate to Monitoring → Active Calls', async () => { await page.goto(`${BASE_URL}/admin/monitoring/active-calls`); }); await test.step('Verify active calls panel loads', async () => { await expect(page.locator('body')).not.toContainText(/500|not found/i); await expect(page.locator('table, .active-calls, .call-panel').first()).toBeVisible(); }); await test.step('Navigate to Monitoring → Registrations', async () => { await page.goto(`${BASE_URL}/admin/monitoring/registrations`); }); await test.step('Verify registrations panel loads', async () => { await expect(page.locator('table, .registrations, .reg-panel').first()).toBeVisible(); }); await test.step('Verify auto-refresh indicator is present', async () => { const autoRefresh = page.locator('[data-refresh],[data-auto-refresh],.refresh-indicator,.last-updated').first(); if (await autoRefresh.count() > 0) { await expect(autoRefresh).toBeVisible(); } }); }); test('pbx-logs-check-detailed_logging_levels_rotation_and_search', async ({ page }, testInfo) => { testInfo.annotations.push({ type: 'automationStatus', description: 'automated' }); testInfo.annotations.push({ type: 'testType', description: 'check' }); testInfo.annotations.push({ type: 'description', description: 'Verify detailed logging levels can be configured, log rotation is set up, and log search/filter is functional' }); await test.step('Navigate to System → Logs', async () => { await page.goto(`${BASE_URL}/admin/logs/system`); }); await test.step('Verify log viewer loads', async () => { await expect(page.locator('body')).not.toContainText(/500|not found/i); await expect(page.locator('.log-viewer, .log-content, pre, textarea').first()).toBeVisible(); }); await test.step('Navigate to log settings (level and rotation)', async () => { await page.goto(`${BASE_URL}/admin/settings/logging`); }); await test.step('Verify log level selector is available', async () => { const levelSelect = page.locator('[name*="log_level"],[id*="log-level"],select').filter({ hasText: /debug|info|warn|error/i }).first(); await expect(levelSelect).toBeVisible(); }); await test.step('Verify log rotation settings are shown', async () => { const pageText = await page.locator('body').textContent() ?? ''; expect(pageText).toMatch(/rotation|rotate|max.*size|keep.*days/i); }); await test.step('Test log search / filter functionality', async () => { await page.goto(`${BASE_URL}/admin/logs/system`); const searchInput = page.locator('[name*="search"],[placeholder*="search"],[placeholder*="filter"]').first(); if (await searchInput.count() > 0) { await searchInput.fill('error'); await page.keyboard.press('Enter'); await expect(page.locator('body')).not.toContainText(/500/i); } }); }); test('pbx-logs-check-threshold_alarms_cpu_channels_disk_memory', async ({ page }, testInfo) => { testInfo.annotations.push({ type: 'automationStatus', description: 'automated' }); testInfo.annotations.push({ type: 'testType', description: 'check' }); testInfo.annotations.push({ type: 'description', description: 'Verify threshold-based alarms are configured for CPU, active channels, disk, and memory usage' }); await test.step('Navigate to Monitoring → Alarms / Thresholds', async () => { await page.goto(`${BASE_URL}/admin/monitoring/alarms`); }); await test.step('Verify alarms page loads', async () => { await expect(page.locator('body')).not.toContainText(/500|not found/i); }); const alarmTypes = ['cpu', 'memory', 'disk', 'channel']; for (const alarmType of alarmTypes) { await test.step(`Verify ${alarmType.toUpperCase()} threshold alarm is configurable`, async () => { const alarmEl = page .locator('tr, .alarm-item, .threshold-item, .metric-row') .filter({ hasText: new RegExp(alarmType, 'i') }); if (await alarmEl.count() > 0) { await expect(alarmEl.first()).toBeVisible(); } }); } await test.step('Verify notification email for alarms is configured', async () => { await page.goto(`${BASE_URL}/admin/settings/notifications`); const emailField = page.locator('[name*="alert_email"],[name*="notif_email"],[type="email"]').first(); if (await emailField.count() > 0) { const value = await emailField.inputValue(); expect(value).toMatch(/@/); } }); }); test('pbx-logs-check-call_quality_metrics_mos_jitter_loss_per_call', async ({ page }, testInfo) => { testInfo.annotations.push({ type: 'automationStatus', description: 'partial' }); testInfo.annotations.push({ type: 'testType', description: 'check' }); markPartial('Quality metrics display and reporting UI can be automated; actual metric generation requires active call sessions with measurable network conditions (jitter, packet loss)'); testInfo.annotations.push({ type: 'description', description: 'Verify per-call quality metrics (MOS score, jitter, packet loss) are collected and displayed in the portal' }); await test.step('Navigate to Reports → Call Quality / QoS', async () => { await page.goto(`${BASE_URL}/admin/reports/call-quality`); }); await test.step('Verify call quality report page loads', async () => { await expect(page.locator('body')).not.toContainText(/500|not found/i); }); await test.step('Verify quality metrics columns are present (MOS, jitter, packet loss)', async () => { const headerText = (await page.locator('thead, .table-header').first().textContent() ?? '').toLowerCase(); const hasQualityMetrics = /mos|jitter|packet.?loss|r.?value/.test(headerText); if (!hasQualityMetrics) { testInfo.annotations.push({ type: 'note', description: 'Quality metrics columns not found — may require active calls or a specific report period to populate' }); } }); await test.step('Verify date range filter is available', async () => { const dateFilter = page.locator('[name*="date"],[name*="range"],input[type="date"]').first(); await expect(dateFilter).toBeVisible(); }); // TODO_MANUAL: Establish calls with controlled network impairment (tc qdisc netem) to generate // measurable jitter and packet loss; verify the portal records accurate MOS scores. }); });