import { test, expect, Page } from '@playwright/test'; /** * Authentication Tests based on feature_list.json * Covers test cases: 5, 7-8, 14-16, 31-34, 35-37 */ const BASE_URL = process.env.PLAYWRIGHT_BASE_URL || 'http://127.0.0.1:3000'; // Helper to login async function login(page: Page) { await page.goto(`${BASE_URL}/login`); await page.fill('#username', 'testuser'); await page.fill('#password', 'Test123456'); await page.click('button[type="submit"]'); await page.waitForURL(`${BASE_URL}/`, { timeout: 10000 }); } test.describe('Authentication Flow', () => { // Test 5: 登录成功 test('should login successfully with valid credentials', async ({ page }) => { await page.goto(`${BASE_URL}/login`); // Fill in credentials using id selectors await page.fill('#username', 'testuser'); await page.fill('#password', 'Test123456'); // Click login and check loading state const loginButton = page.locator('button[type="submit"]'); await loginButton.click(); // Verify loading state await expect(loginButton).toContainText('登录中'); // Wait for navigation await page.waitForURL(`${BASE_URL}/`, { timeout: 10000 }); // Verify redirected to home await expect(page).toHaveURL(`${BASE_URL}/`); // Verify user avatar is visible in navbar const avatar = page.locator('[data-testid="user-avatar"]').or(page.locator('.avatar')).first(); await expect(avatar).toBeVisible(); }); // Test 7: 已登录用户访问登录页自动重定向 test('should redirect logged-in user from login page to home', async ({ page }) => { await login(page); // Try to access login page again await page.goto(`${BASE_URL}/login`); // Should be redirected to home await expect(page).toHaveURL(`${BASE_URL}/`); }); // Test 8: 登录后重定向到原页面 test('should redirect to original page after login', async ({ page }) => { // Access protected page while logged out await page.goto(`${BASE_URL}/canvas`); // Should be redirected to login with redirect param await expect(page).toHaveURL(/.*login.*/); await expect(page).toHaveURL(/.*redirect=.*/); // Login await page.fill('#username', 'testuser'); await page.fill('#password', 'Test123456'); await page.click('button[type="submit"]'); // Should redirect back to original page await page.waitForURL(`${BASE_URL}/canvas`, { timeout: 10000 }); await expect(page).toHaveURL(`${BASE_URL}/canvas`); }); // Test 14: 注册失败 - 用户名已存在 test('should show error for existing username during registration', async ({ page }) => { await page.goto(`${BASE_URL}/register`); await page.fill('#username', 'testuser'); await page.fill('#email', 'unique@example.com'); await page.fill('#password', 'Test123456'); await page.fill('#confirmPassword', 'Test123456'); await page.click('button[type="submit"]'); // Should show error about existing user await expect(page.locator('text=/already registered|已注册|用户名已存在|Username already exists/i').first()).toBeVisible({ timeout: 5000 }); }); // Test 15: 注册成功 test('should register successfully with new user', async ({ page }) => { await page.goto(`${BASE_URL}/register`); const timestamp = Date.now(); await page.fill('#username', `newuser${timestamp}`); await page.fill('#email', `newuser${timestamp}@example.com`); await page.fill('#password', 'Test123456'); await page.fill('#confirmPassword', 'Test123456'); const registerButton = page.locator('button[type="submit"]'); await registerButton.click(); // Verify loading state await expect(registerButton).toContainText('注册中'); // Wait for navigation to home await page.waitForURL(`${BASE_URL}/`, { timeout: 10000 }); await expect(page).toHaveURL(`${BASE_URL}/`); // Verify avatar is visible const avatar = page.locator('[data-testid="user-avatar"]').or(page.locator('.avatar')).first(); await expect(avatar).toBeVisible(); }); // Test 16: 已登录用户访问注册页自动重定向 test('should redirect logged-in user from register page to home', async ({ page }) => { await login(page); // Try to access register page await page.goto(`${BASE_URL}/register`); // Should be redirected to home await expect(page).toHaveURL(`${BASE_URL}/`); }); }); test.describe('User Menu', () => { // Test 31: 已登录状态显示用户头像 test('should display user avatar when logged in', async ({ page }) => { await login(page); // Check avatar is visible const avatar = page.locator('[data-testid="user-avatar"]').or(page.locator('.avatar')).first(); await expect(avatar).toBeVisible(); // Check it shows first letter of username await expect(avatar).toContainText('T'); // 'testuser' starts with T }); // Test 32: 点击头像显示下拉菜单 test('should show dropdown menu when clicking avatar', async ({ page }) => { await login(page); // Click avatar const avatar = page.locator('[data-testid="user-avatar"]').or(page.locator('.avatar')).first(); await avatar.click(); // Verify dropdown shows username and email await expect(page.locator('text=testuser').first()).toBeVisible(); await expect(page.locator('text=/API Keys|API 密钥/i').first()).toBeVisible(); await expect(page.locator('text=/Log out|退出|登出/i').first()).toBeVisible(); }); // Test 33: 点击 API Keys 菜单项跳转 test('should navigate to API Keys page from dropdown', async ({ page }) => { await login(page); // Click avatar const avatar = page.locator('[data-testid="user-avatar"]').or(page.locator('.avatar')).first(); await avatar.click(); // Click API Keys await page.click('text=/API Keys|API 密钥/i'); // Should navigate to api-keys page await expect(page).toHaveURL(`${BASE_URL}/canvas`); }); // Test 34: 点击 Log out 登出 test('should logout when clicking logout', async ({ page }) => { await login(page); // Click avatar const avatar = page.locator('[data-testid="user-avatar"]').or(page.locator('.avatar')).first(); await avatar.click(); // Click logout await page.click('text=/Log out|退出|登出/i'); // Should redirect to login or home await page.waitForLoadState('networkidle'); const url = page.url(); expect(url.includes('/login') || url === `${BASE_URL}/`).toBeTruthy(); // Verify login icon is shown (user is logged out) const loginIcon = page.locator('[data-testid="login-icon"]').or(page.locator('a[href="/login"]')).first(); await expect(loginIcon).toBeVisible(); }); }); test.describe('Route Protection', () => { // Test 35: 访问 /settings/* 需要登录 test('should redirect to login when accessing settings without auth', async ({ page }) => { await page.goto(`${BASE_URL}/canvas`); // Should be redirected to login await expect(page).toHaveURL(/.*login.*/); }); // Test 36: 已登录用户访问登录/注册页重定向 test('should redirect authenticated users from auth pages', async ({ page }) => { await login(page); // Try accessing login await page.goto(`${BASE_URL}/login`); await expect(page).toHaveURL(`${BASE_URL}/`); // Try accessing register await page.goto(`${BASE_URL}/register`); await expect(page).toHaveURL(`${BASE_URL}/`); }); // Test 37: 访问公开页面无需登录 test('should allow access to public pages without auth', async ({ page }) => { await page.goto(`${BASE_URL}/`); // Should stay on home page await expect(page).toHaveURL(`${BASE_URL}/`); // Should not redirect to login await expect(page).not.toHaveURL(/.*login.*/); }); });