import { test, expect } from '@playwright/test'; /** * Navigation and Routing E2E Tests * * Tests basic navigation, routing, and page loads */ test.describe('Basic Navigation', () => { test('should load homepage without errors', async ({ page }) => { // Navigate to homepage const response = await page.goto('/'); // Page should load successfully expect(response?.status()).toBe(200); // Page should have a title await expect(page).toHaveTitle(/GAMILIT|Gamificación/i); // Page should not have console errors const errors: string[] = []; page.on('console', (msg) => { if (msg.type() === 'error') { errors.push(msg.text()); } }); // Wait a bit for any async errors await page.waitForTimeout(2000); // Should have minimal or no errors expect(errors.length).toBeLessThan(5); // Allow for some dev warnings }); test('should handle 404 pages', async ({ page }) => { const response = await page.goto('/this-page-does-not-exist'); // Should either show 404 page or redirect const url = page.url(); const statusCode = response?.status(); // Accept either a 404 status OR redirect to home/login const isValid = statusCode === 404 || url.includes('/login') || url === 'http://localhost:3005/'; expect(isValid).toBeTruthy(); }); test('should have responsive navigation menu', async ({ page }) => { await page.goto('/'); // Check if navigation exists (either as sidebar or header) const hasNav = (await page.locator('nav').count()) > 0 || (await page.locator('[role="navigation"]').count()) > 0; expect(hasNav).toBeTruthy(); }); test('should load without JavaScript errors', async ({ page }) => { const jsErrors: Error[] = []; page.on('pageerror', (error) => { jsErrors.push(error); }); await page.goto('/'); // Wait for page to fully load await page.waitForLoadState('networkidle'); // Should have no JavaScript errors expect(jsErrors.length).toBe(0); }); test('should have proper meta tags', async ({ page }) => { await page.goto('/'); // Check for viewport meta tag (important for mobile) const viewport = await page.locator('meta[name="viewport"]').getAttribute('content'); expect(viewport).toContain('width=device-width'); // Check for charset const hasCharset = (await page.locator('meta[charset]').count()) > 0 || (await page.locator('meta[charset="utf-8"]').count()) > 0 || (await page.locator('meta[charset="UTF-8"]').count()) > 0; expect(hasCharset).toBeTruthy(); }); }); test.describe('Protected Routes', () => { test('should redirect to login when accessing protected routes unauthenticated', async ({ page, }) => { // Try to access a protected route (e.g., dashboard) await page.goto('/dashboard'); // Should redirect to login page await expect(page).toHaveURL(/\/login|\//); }); test('should redirect to login when accessing student pages unauthenticated', async ({ page, }) => { await page.goto('/student/dashboard'); // Should redirect to login await expect(page).toHaveURL(/\/login|\//); }); test('should redirect to login when accessing teacher pages unauthenticated', async ({ page, }) => { await page.goto('/teacher/dashboard'); // Should redirect to login await expect(page).toHaveURL(/\/login|\//); }); }); test.describe('Performance', () => { test('should load initial page within acceptable time', async ({ page }) => { const startTime = Date.now(); await page.goto('/'); await page.waitForLoadState('domcontentloaded'); const loadTime = Date.now() - startTime; // Should load within 5 seconds (generous for E2E) expect(loadTime).toBeLessThan(5000); }); test('should not have memory leaks on navigation', async ({ page }) => { await page.goto('/'); // Navigate between pages multiple times for (let i = 0; i < 3; i++) { await page.goto('/'); await page.waitForLoadState('networkidle'); // Try to navigate to other pages if they exist const links = await page.locator('a[href^="/"]').all(); if (links.length > 0) { await links[0].click(); await page.waitForLoadState('networkidle'); } await page.goBack(); } // If no errors thrown, test passes expect(true).toBeTruthy(); }); }); test.describe('Accessibility Basics', () => { test('should have proper heading hierarchy', async ({ page }) => { await page.goto('/'); // Check for h1 const h1Count = await page.locator('h1').count(); expect(h1Count).toBeGreaterThan(0); expect(h1Count).toBeLessThanOrEqual(1); // Should have only one h1 }); test('should have skip to content link for keyboard users', async ({ page }) => { await page.goto('/'); // Check for skip link (common accessibility practice) const skipLink = page.locator('a[href="#main-content"], a[href="#content"]'); // Skip link may or may not be present, but if it is, it should work if ((await skipLink.count()) > 0) { await expect(skipLink).toBeAttached(); } }); test('should be keyboard navigable', async ({ page }) => { await page.goto('/'); // Press Tab key to navigate await page.keyboard.press('Tab'); // Check if focus is visible somewhere const focusedElement = await page.evaluate(() => { return document.activeElement?.tagName; }); // Should have moved focus to some element expect(focusedElement).toBeTruthy(); }); });