|
|
@@ -0,0 +1,212 @@
|
|
|
+import { test, expect } from '../../utils/test-setup';
|
|
|
+import testUsers from '../../fixtures/test-users.json' with { type: 'json' };
|
|
|
+
|
|
|
+test.describe('登录页面 E2E 测试', () => {
|
|
|
+ test.beforeEach(async ({ page, adminLoginPage }) => {
|
|
|
+ await adminLoginPage.goto();
|
|
|
+ });
|
|
|
+
|
|
|
+ test('登录页面加载', async ({ adminLoginPage }) => {
|
|
|
+ await adminLoginPage.expectToBeVisible();
|
|
|
+ await expect(adminLoginPage.pageTitle).toHaveText('管理后台登录');
|
|
|
+ await expect(adminLoginPage.welcomeText).toBeVisible();
|
|
|
+ });
|
|
|
+
|
|
|
+ test('成功登录', async ({ adminLoginPage, dashboardPage }) => {
|
|
|
+ // 使用有效凭据登录
|
|
|
+ await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
|
|
|
+
|
|
|
+ // 验证跳转到仪表盘
|
|
|
+ await dashboardPage.expectToBeVisible();
|
|
|
+ await expect(dashboardPage.pageTitle).toHaveText('仪表盘');
|
|
|
+
|
|
|
+ // 验证成功 toast 显示
|
|
|
+ await expect(adminLoginPage.successToast).toBeVisible();
|
|
|
+ await expect(adminLoginPage.successToast).toContainText('登录成功');
|
|
|
+ });
|
|
|
+
|
|
|
+ test('登录失败 - 错误密码', async ({ adminLoginPage }) => {
|
|
|
+ // 使用错误密码尝试登录
|
|
|
+ await adminLoginPage.login(testUsers.admin.username, 'wrongpassword');
|
|
|
+
|
|
|
+ // 验证错误消息显示
|
|
|
+ await expect(adminLoginPage.errorToast).toBeVisible();
|
|
|
+ await expect(adminLoginPage.errorToast).toContainText('登录失败');
|
|
|
+
|
|
|
+ // 验证仍然在登录页面
|
|
|
+ await adminLoginPage.expectToBeVisible();
|
|
|
+ });
|
|
|
+
|
|
|
+ test('登录失败 - 不存在的用户', async ({ adminLoginPage }) => {
|
|
|
+ // 使用不存在的用户尝试登录
|
|
|
+ await adminLoginPage.login('nonexistentuser', 'anypassword');
|
|
|
+
|
|
|
+ // 验证错误消息显示
|
|
|
+ await expect(adminLoginPage.errorToast).toBeVisible();
|
|
|
+ await expect(adminLoginPage.errorToast).toContainText('登录失败');
|
|
|
+
|
|
|
+ // 验证仍然在登录页面
|
|
|
+ await adminLoginPage.expectToBeVisible();
|
|
|
+ });
|
|
|
+
|
|
|
+ test('表单验证 - 空用户名', async ({ adminLoginPage }) => {
|
|
|
+ // 不填写用户名直接提交
|
|
|
+ await adminLoginPage.passwordInput.fill('password');
|
|
|
+ await adminLoginPage.submitButton.click();
|
|
|
+
|
|
|
+ // 验证验证错误显示
|
|
|
+ await expect(adminLoginPage.usernameError).toBeVisible();
|
|
|
+ await expect(adminLoginPage.usernameError).toContainText('请输入用户名');
|
|
|
+ });
|
|
|
+
|
|
|
+ test('表单验证 - 空密码', async ({ adminLoginPage }) => {
|
|
|
+ // 不填写密码直接提交
|
|
|
+ await adminLoginPage.usernameInput.fill('admin');
|
|
|
+ await adminLoginPage.submitButton.click();
|
|
|
+
|
|
|
+ // 验证验证错误显示
|
|
|
+ await expect(adminLoginPage.passwordError).toBeVisible();
|
|
|
+ await expect(adminLoginPage.passwordError).toContainText('请输入密码');
|
|
|
+ });
|
|
|
+
|
|
|
+ test('密码可见性切换', async ({ adminLoginPage }) => {
|
|
|
+ // 初始状态密码应该被隐藏
|
|
|
+ await expect(adminLoginPage.passwordInput).toHaveAttribute('type', 'password');
|
|
|
+
|
|
|
+ // 点击显示密码按钮
|
|
|
+ await adminLoginPage.togglePasswordButton.click();
|
|
|
+
|
|
|
+ // 验证密码可见
|
|
|
+ await expect(adminLoginPage.passwordInput).toHaveAttribute('type', 'text');
|
|
|
+
|
|
|
+ // 再次点击隐藏密码
|
|
|
+ await adminLoginPage.togglePasswordButton.click();
|
|
|
+
|
|
|
+ // 验证密码隐藏
|
|
|
+ await expect(adminLoginPage.passwordInput).toHaveAttribute('type', 'password');
|
|
|
+ });
|
|
|
+
|
|
|
+ test('测试账号信息显示', async ({ adminLoginPage }) => {
|
|
|
+ // 验证测试账号信息存在
|
|
|
+ await expect(adminLoginPage.testAccountInfo).toBeVisible();
|
|
|
+ await expect(adminLoginPage.testAccountInfo).toContainText('admin');
|
|
|
+ await expect(adminLoginPage.testAccountInfo).toContainText('admin123');
|
|
|
+ });
|
|
|
+
|
|
|
+ test('使用测试账号登录', async ({ adminLoginPage, dashboardPage }) => {
|
|
|
+ // 使用测试账号信息登录
|
|
|
+ await adminLoginPage.usernameInput.fill('admin');
|
|
|
+ await adminLoginPage.passwordInput.fill('admin123');
|
|
|
+ await adminLoginPage.submitButton.click();
|
|
|
+
|
|
|
+ // 验证登录成功
|
|
|
+ await dashboardPage.expectToBeVisible();
|
|
|
+ await expect(dashboardPage.pageTitle).toHaveText('仪表盘');
|
|
|
+ });
|
|
|
+
|
|
|
+ test('登录页面样式和布局', async ({ adminLoginPage, page }) => {
|
|
|
+ // 验证背景渐变
|
|
|
+ await expect(adminLoginPage.backgroundElement).toHaveClass(/bg-gradient/);
|
|
|
+
|
|
|
+ // 验证卡片阴影
|
|
|
+ await expect(adminLoginPage.loginCard).toHaveClass(/shadow/);
|
|
|
+
|
|
|
+ // 验证响应式设计
|
|
|
+ await page.setViewportSize({ width: 375, height: 667 });
|
|
|
+ await adminLoginPage.expectToBeVisible();
|
|
|
+
|
|
|
+ // 移动端布局验证
|
|
|
+ await expect(adminLoginPage.pageTitle).toBeVisible();
|
|
|
+ await expect(adminLoginPage.usernameInput).toBeVisible();
|
|
|
+ await expect(adminLoginPage.passwordInput).toBeVisible();
|
|
|
+ });
|
|
|
+
|
|
|
+ test('登录后刷新保持登录状态', async ({ adminLoginPage, dashboardPage, page }) => {
|
|
|
+ // 先登录
|
|
|
+ await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
|
|
|
+ await dashboardPage.expectToBeVisible();
|
|
|
+
|
|
|
+ // 刷新页面
|
|
|
+ await page.reload();
|
|
|
+
|
|
|
+ // 验证仍然保持登录状态
|
|
|
+ await dashboardPage.expectToBeVisible();
|
|
|
+ await expect(dashboardPage.pageTitle).toHaveText('仪表盘');
|
|
|
+ });
|
|
|
+
|
|
|
+ test('登出后重定向到登录页', async ({ adminLoginPage, dashboardPage, page }) => {
|
|
|
+ // 先登录
|
|
|
+ await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
|
|
|
+ await dashboardPage.expectToBeVisible();
|
|
|
+
|
|
|
+ // 执行登出
|
|
|
+ await dashboardPage.logout();
|
|
|
+
|
|
|
+ // 验证重定向到登录页
|
|
|
+ await adminLoginPage.expectToBeVisible();
|
|
|
+ await expect(adminLoginPage.pageTitle).toHaveText('管理后台登录');
|
|
|
+
|
|
|
+ // 验证不能直接访问受保护页面
|
|
|
+ await page.goto('/admin/dashboard');
|
|
|
+ await adminLoginPage.expectToBeVisible(); // 应该重定向回登录页
|
|
|
+ });
|
|
|
+
|
|
|
+ test('多标签页登录状态同步', async ({ adminLoginPage, dashboardPage, context }) => {
|
|
|
+ // 在第一个标签页登录
|
|
|
+ await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
|
|
|
+ await dashboardPage.expectToBeVisible();
|
|
|
+
|
|
|
+ // 打开第二个标签页
|
|
|
+ const newPage = await context.newPage();
|
|
|
+ await newPage.goto('/admin/dashboard');
|
|
|
+
|
|
|
+ // 验证第二个标签页也自动登录
|
|
|
+ const newDashboardPage = dashboardPage.clone(newPage);
|
|
|
+ await newDashboardPage.expectToBeVisible();
|
|
|
+
|
|
|
+ // 在第一个标签页登出
|
|
|
+ await dashboardPage.logout();
|
|
|
+ await adminLoginPage.expectToBeVisible();
|
|
|
+
|
|
|
+ // 验证第二个标签页也登出
|
|
|
+ await newPage.reload();
|
|
|
+ const newLoginPage = adminLoginPage.clone(newPage);
|
|
|
+ await newLoginPage.expectToBeVisible();
|
|
|
+ });
|
|
|
+
|
|
|
+ test('登录加载状态显示', async ({ adminLoginPage }) => {
|
|
|
+ // 填写登录信息
|
|
|
+ await adminLoginPage.usernameInput.fill('admin');
|
|
|
+ await adminLoginPage.passwordInput.fill('admin123');
|
|
|
+
|
|
|
+ // 提交表单
|
|
|
+ await adminLoginPage.submitButton.click();
|
|
|
+
|
|
|
+ // 验证加载状态显示
|
|
|
+ await expect(adminLoginPage.loadingSpinner).toBeVisible();
|
|
|
+ await expect(adminLoginPage.submitButton).toBeDisabled();
|
|
|
+
|
|
|
+ // 等待加载完成
|
|
|
+ await expect(adminLoginPage.loadingSpinner).not.toBeVisible();
|
|
|
+ });
|
|
|
+
|
|
|
+ test('浏览器返回按钮行为', async ({ adminLoginPage, dashboardPage, page }) => {
|
|
|
+ // 先登录
|
|
|
+ await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
|
|
|
+ await dashboardPage.expectToBeVisible();
|
|
|
+
|
|
|
+ // 点击浏览器返回按钮
|
|
|
+ await page.goBack();
|
|
|
+
|
|
|
+ // 验证不会返回到登录页(应该停留在仪表盘或重定向)
|
|
|
+ try {
|
|
|
+ await adminLoginPage.expectToBeVisible({ timeout: 2000 });
|
|
|
+ // 如果看到登录页,再次前进
|
|
|
+ await page.goForward();
|
|
|
+ await dashboardPage.expectToBeVisible();
|
|
|
+ } catch {
|
|
|
+ // 如果没看到登录页,说明行为正确
|
|
|
+ await dashboardPage.expectToBeVisible();
|
|
|
+ }
|
|
|
+ });
|
|
|
+});
|