more fixes
This commit is contained in:
149
tests/cpad/auth.spec.ts
Normal file
149
tests/cpad/auth.spec.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Authentication tests for the cPad Control Panel.
|
||||
*
|
||||
* Coverage:
|
||||
* • Login page renders correctly
|
||||
* • Login with valid credentials → redirected to /cp/dashboard (or /cp/)
|
||||
* • Login with invalid credentials → error message shown, no redirect
|
||||
* • Logout → session is destroyed, login page is shown
|
||||
*
|
||||
* These tests do NOT use the pre-saved storageState; they exercise the actual
|
||||
* login/logout flow from scratch.
|
||||
*
|
||||
* Run:
|
||||
* npx playwright test tests/cpad/auth.spec.ts --project=chromium
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import {
|
||||
ADMIN_EMAIL,
|
||||
ADMIN_PASSWORD,
|
||||
CP_PATH,
|
||||
DASHBOARD_PATH,
|
||||
attachErrorListeners,
|
||||
} from '../helpers/auth';
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Login page
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
test.describe('cPad Login Page', () => {
|
||||
test('login page loads and shows email + password fields', async ({ page }) => {
|
||||
const { consoleErrors, networkErrors } = attachErrorListeners(page);
|
||||
|
||||
await page.goto(CP_PATH + '/login');
|
||||
|
||||
// Basic page health
|
||||
await expect(page.locator('body')).toBeVisible();
|
||||
const title = await page.title();
|
||||
expect(title.length, 'Page title should not be empty').toBeGreaterThan(0);
|
||||
|
||||
// Form fields
|
||||
const emailField = page.locator('input[name="email"], input[type="email"]').first();
|
||||
const passwordField = page.locator('input[name="password"], input[type="password"]').first();
|
||||
const submitButton = page.locator('button[type="submit"], input[type="submit"]').first();
|
||||
|
||||
await expect(emailField).toBeVisible();
|
||||
await expect(passwordField).toBeVisible();
|
||||
await expect(submitButton).toBeVisible();
|
||||
|
||||
// No JS crashes on page load
|
||||
expect(consoleErrors.length, `Console errors: ${consoleErrors.join(' | ')}`).toBe(0);
|
||||
expect(networkErrors.length, `Network errors: ${networkErrors.join(' | ')}`).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Successful login
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
test.describe('cPad Successful Login', () => {
|
||||
test('admin can log in and is redirected to dashboard', async ({ page }) => {
|
||||
const { consoleErrors, networkErrors } = attachErrorListeners(page);
|
||||
|
||||
await page.goto(CP_PATH + '/login');
|
||||
|
||||
await page.locator('input[name="email"], input[type="email"]').first().fill(ADMIN_EMAIL);
|
||||
await page.locator('input[name="password"], input[type="password"]').first().fill(ADMIN_PASSWORD);
|
||||
await page.locator('button[type="submit"], input[type="submit"]').first().click();
|
||||
|
||||
// After successful login the URL should be within /cp and not be /login
|
||||
await page.waitForURL(
|
||||
(url) => url.pathname.startsWith(CP_PATH) && !url.pathname.endsWith('/login'),
|
||||
{ timeout: 20_000 },
|
||||
);
|
||||
|
||||
await expect(page.locator('body')).toBeVisible();
|
||||
|
||||
// No server errors
|
||||
const body = await page.locator('body').textContent() ?? '';
|
||||
expect(/Whoops|Server Error|500/.test(body), 'Server error page after login').toBe(false);
|
||||
|
||||
expect(networkErrors.length, `HTTP 5xx errors: ${networkErrors.join(' | ')}`).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Failed login
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
test.describe('cPad Failed Login', () => {
|
||||
test('wrong password shows error and stays on login page', async ({ page }) => {
|
||||
const { networkErrors } = attachErrorListeners(page);
|
||||
|
||||
await page.goto(CP_PATH + '/login');
|
||||
|
||||
await page.locator('input[name="email"], input[type="email"]').first().fill(ADMIN_EMAIL);
|
||||
await page.locator('input[name="password"], input[type="password"]').first().fill('WrongPassword999!');
|
||||
await page.locator('button[type="submit"], input[type="submit"]').first().click();
|
||||
|
||||
// Should stay on the login page
|
||||
await page.waitForLoadState('networkidle');
|
||||
expect(page.url()).toContain('/login');
|
||||
|
||||
// No 5xx errors from a bad credentials attempt
|
||||
expect(networkErrors.length, `HTTP 5xx errors: ${networkErrors.join(' | ')}`).toBe(0);
|
||||
});
|
||||
|
||||
test('empty credentials show validation errors', async ({ page }) => {
|
||||
await page.goto(CP_PATH + '/login');
|
||||
|
||||
// Submit without filling in anything
|
||||
await page.locator('button[type="submit"], input[type="submit"]').first().click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Still on login page
|
||||
expect(page.url()).toContain(CP_PATH);
|
||||
});
|
||||
});
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Logout
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
test.describe('cPad Logout', () => {
|
||||
test('logout destroys session and shows login page', async ({ page }) => {
|
||||
// Log in first
|
||||
await page.goto(CP_PATH + '/login');
|
||||
await page.locator('input[name="email"], input[type="email"]').first().fill(ADMIN_EMAIL);
|
||||
await page.locator('input[name="password"], input[type="password"]').first().fill(ADMIN_PASSWORD);
|
||||
await page.locator('button[type="submit"], input[type="submit"]').first().click();
|
||||
|
||||
await page.waitForURL(
|
||||
(url) => url.pathname.startsWith(CP_PATH) && !url.pathname.endsWith('/login'),
|
||||
{ timeout: 20_000 },
|
||||
);
|
||||
|
||||
// Perform logout via the /cp/logout route
|
||||
await page.goto(CP_PATH + '/logout');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Should land on the login page again
|
||||
expect(page.url()).toContain('/login');
|
||||
|
||||
// Attempting to access dashboard now should redirect back to login
|
||||
await page.goto(DASHBOARD_PATH);
|
||||
await page.waitForLoadState('networkidle');
|
||||
expect(page.url()).toContain('/login');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user