/** * Dashboard tests for the cPad Control Panel. * * Uses the pre-saved authenticated session (tests/.auth/admin.json) so no * explicit login is required in each test. * * Coverage: * • Dashboard page loads (HTTP 200, not a Laravel error page) * • Page title is not empty * • No JavaScript console errors * • No HTTP 5xx responses * • Key dashboard elements are visible (sidebar, main content area) * • Dashboard setup page loads * * Run: * npx playwright test tests/cpad/dashboard.spec.ts --project=cpad */ import { test, expect } from '@playwright/test'; import { DASHBOARD_PATH, CP_PATH, attachErrorListeners } from '../helpers/auth'; test.describe('cPad Dashboard', () => { test('dashboard page loads without errors', async ({ page }) => { const { consoleErrors, networkErrors } = attachErrorListeners(page); await page.goto(DASHBOARD_PATH); await page.waitForLoadState('networkidle'); // Must not be redirected to login expect(page.url(), 'Should not redirect to login').not.toContain('/login'); // Title check const title = await page.title(); expect(title.length, 'Page must have a non-empty title').toBeGreaterThan(0); // Body must be visible await expect(page.locator('body')).toBeVisible(); // No server error page const bodyText = await page.locator('body').textContent() ?? ''; expect(/Whoops|Server Error|5[0-9]{2}/.test(bodyText), 'Server error detected in body').toBe(false); // No JS exceptions expect(consoleErrors.length, `Console errors: ${consoleErrors.join(' | ')}`).toBe(0); expect(networkErrors.length, `HTTP 5xx: ${networkErrors.join(' | ')}`).toBe(0); }); test('dashboard root redirect works', async ({ page }) => { const { networkErrors } = attachErrorListeners(page); // /cp redirects to /cp/dashboard await page.goto(CP_PATH); await page.waitForLoadState('networkidle'); expect(page.url(), 'Should not be on login page').not.toContain('/login'); expect(networkErrors.length, `HTTP 5xx: ${networkErrors.join(' | ')}`).toBe(0); }); test('dashboard has visible sidebar or navigation', async ({ page }) => { await page.goto(DASHBOARD_PATH); await page.waitForLoadState('networkidle'); // Check for a nav/sidebar element — any of these common AdminLTE/Bootstrap selectors const navSelectors = [ 'nav', '.sidebar', '#sidebar', '.main-sidebar', '#main-sidebar', '[data-testid="sidebar"]', '.navbar', ]; let foundNav = false; for (const sel of navSelectors) { const count = await page.locator(sel).count(); if (count > 0) { foundNav = true; break; } } expect(foundNav, 'Dashboard should contain a sidebar or navigation element').toBe(true); }); test('dashboard main content area is visible', async ({ page }) => { await page.goto(DASHBOARD_PATH); await page.waitForLoadState('networkidle'); // Any of these indicate a main content wrapper is rendered const contentSelectors = [ 'main', '#content', '.content-wrapper', '.main-content', '[data-testid="main-content"]', '.wrapper', ]; let foundContent = false; for (const sel of contentSelectors) { const count = await page.locator(sel).count(); if (count > 0) { foundContent = true; break; } } expect(foundContent, 'Dashboard main content area should be present').toBe(true); }); test('dashboard setup page loads', async ({ page }) => { const { consoleErrors, networkErrors } = attachErrorListeners(page); await page.goto(CP_PATH + '/dashboard/setup'); await page.waitForLoadState('networkidle'); expect(page.url()).not.toContain('/login'); expect(consoleErrors.length, `Console errors: ${consoleErrors.join(' | ')}`).toBe(0); expect(networkErrors.length, `Network errors: ${networkErrors.join(' | ')}`).toBe(0); }); });