/** * Student portal smoke + happy-path coverage. */ import { test, expect } from '@playwright/test'; import { loginAs } from '../helpers/auth'; import { ROUTES_PER_ROLE, ROLE_LANDING } from '../helpers/nav'; import { captureConsoleErrors, expectNoConsoleErrors, expectPageMounted, } from '../helpers/assertions'; const BASE = 'http://localhost:3000'; const STUDENT_CHROME = ['Africa Alert', 'Student', 'Dashboard']; test.describe('Student portal — smoke @smoke', () => { test.beforeEach(async ({ page }) => { await loginAs(page, 'student'); }); for (const route of ROUTES_PER_ROLE.student) { test(`mounts ${route}`, async ({ page }) => { const cap = captureConsoleErrors(page); try { await page.goto(`${BASE}${route}`); await expectPageMounted(page, route, [route.split('/').pop() || route, ...STUDENT_CHROME]); } finally { cap.dispose(); expectNoConsoleErrors(cap.errors); } }); } }); test.describe('Student portal — happy path @flow', () => { test.beforeEach(async ({ page }) => { await loginAs(page, 'student'); }); test('lands on the student dashboard after login', async ({ page }) => { await page.goto(`${BASE}/`); await expect(page).toHaveURL(new RegExp(`${ROLE_LANDING.student.replace(/\//g, '\\/')}$`)); }); test('grades: page shows grades list or empty state', async ({ page }) => { await page.goto(`${BASE}/grades`); await expect(page.locator('h1, h2').first()).toBeVisible(); const tableOrEmpty = page .locator('table') .or(page.getByText(/no grades|no records|empty/i)); await expect(tableOrEmpty.first()).toBeVisible({ timeout: 5_000 }); }); test('assignments: list page is reachable', async ({ page }) => { await page.goto(`${BASE}/assignments`); await expect(page.locator('h1, h2').first()).toBeVisible(); }); test('my-courses: course list page renders', async ({ page }) => { await page.goto(`${BASE}/my-courses`); await expect(page.locator('h1, h2').first()).toBeVisible(); }); test('fees: page renders fee summary', async ({ page }) => { await page.goto(`${BASE}/fees`); await expect(page.locator('h1, h2').first()).toBeVisible(); // Look for a Paynow / pay button, an amount, or a fees table. const feeSurface = page .getByRole('button', { name: /pay|paynow/i }) .or(page.getByText(/balance|outstanding|total/i)) .or(page.locator('table')); await expect(feeSurface.first()).toBeVisible({ timeout: 5_000 }); }); test('exams: list page is reachable', async ({ page }) => { await page.goto(`${BASE}/exams`); await expect(page.locator('h1, h2').first()).toBeVisible(); }); });