123 lines
3.9 KiB
TypeScript
123 lines
3.9 KiB
TypeScript
/**
|
|
* 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);
|
|
});
|
|
});
|