login.spec.ts 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import { test, expect } from '../../utils/test-setup';
  2. import testUsers from '../../fixtures/test-users.json' with { type: 'json' };
  3. test.describe('登录页面 E2E 测试', () => {
  4. test.beforeEach(async ({ page, adminLoginPage }) => {
  5. await adminLoginPage.goto();
  6. });
  7. test('登录页面加载', async ({ adminLoginPage }) => {
  8. await adminLoginPage.expectToBeVisible();
  9. await expect(adminLoginPage.pageTitle).toHaveText('管理后台登录');
  10. await expect(adminLoginPage.welcomeText).toBeVisible();
  11. });
  12. test('成功登录', async ({ adminLoginPage, dashboardPage }) => {
  13. // 使用有效凭据登录
  14. await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
  15. // 验证跳转到仪表盘
  16. await dashboardPage.expectToBeVisible();
  17. await expect(dashboardPage.pageTitle).toHaveText('仪表盘');
  18. // 验证成功 toast 显示
  19. await expect(adminLoginPage.successToast).toBeVisible();
  20. await expect(adminLoginPage.successToast).toContainText('登录成功');
  21. });
  22. test('登录失败 - 错误密码', async ({ adminLoginPage }) => {
  23. // 使用错误密码尝试登录
  24. await adminLoginPage.login(testUsers.admin.username, 'wrongpassword');
  25. // 验证错误消息显示
  26. await expect(adminLoginPage.errorToast).toBeVisible();
  27. await expect(adminLoginPage.errorToast).toContainText('登录失败');
  28. // 验证仍然在登录页面
  29. await adminLoginPage.expectToBeVisible();
  30. });
  31. test('登录失败 - 不存在的用户', async ({ adminLoginPage }) => {
  32. // 使用不存在的用户尝试登录
  33. await adminLoginPage.login('nonexistentuser', 'anypassword');
  34. // 验证错误消息显示
  35. await expect(adminLoginPage.errorToast).toBeVisible();
  36. await expect(adminLoginPage.errorToast).toContainText('登录失败');
  37. // 验证仍然在登录页面
  38. await adminLoginPage.expectToBeVisible();
  39. });
  40. test('表单验证 - 空用户名', async ({ adminLoginPage }) => {
  41. // 不填写用户名直接提交
  42. await adminLoginPage.passwordInput.fill('password');
  43. await adminLoginPage.submitButton.click();
  44. // 验证验证错误显示
  45. await expect(adminLoginPage.usernameError).toBeVisible();
  46. await expect(adminLoginPage.usernameError).toContainText('请输入用户名');
  47. });
  48. test('表单验证 - 空密码', async ({ adminLoginPage }) => {
  49. // 不填写密码直接提交
  50. await adminLoginPage.usernameInput.fill('admin');
  51. await adminLoginPage.submitButton.click();
  52. // 验证验证错误显示
  53. await expect(adminLoginPage.passwordError).toBeVisible();
  54. await expect(adminLoginPage.passwordError).toContainText('请输入密码');
  55. });
  56. test('密码可见性切换', async ({ adminLoginPage }) => {
  57. // 初始状态密码应该被隐藏
  58. await expect(adminLoginPage.passwordInput).toHaveAttribute('type', 'password');
  59. // 点击显示密码按钮
  60. await adminLoginPage.togglePasswordButton.click();
  61. // 验证密码可见
  62. await expect(adminLoginPage.passwordInput).toHaveAttribute('type', 'text');
  63. // 再次点击隐藏密码
  64. await adminLoginPage.togglePasswordButton.click();
  65. // 验证密码隐藏
  66. await expect(adminLoginPage.passwordInput).toHaveAttribute('type', 'password');
  67. });
  68. test('测试账号信息显示', async ({ adminLoginPage }) => {
  69. // 验证测试账号信息存在
  70. await expect(adminLoginPage.testAccountInfo).toBeVisible();
  71. await expect(adminLoginPage.testAccountInfo).toContainText('admin');
  72. await expect(adminLoginPage.testAccountInfo).toContainText('admin123');
  73. });
  74. test('使用测试账号登录', async ({ adminLoginPage, dashboardPage }) => {
  75. // 使用测试账号信息登录
  76. await adminLoginPage.usernameInput.fill('admin');
  77. await adminLoginPage.passwordInput.fill('admin123');
  78. await adminLoginPage.submitButton.click();
  79. // 验证登录成功
  80. await dashboardPage.expectToBeVisible();
  81. await expect(dashboardPage.pageTitle).toHaveText('仪表盘');
  82. });
  83. test('登录页面样式和布局', async ({ adminLoginPage, page }) => {
  84. // 验证背景渐变
  85. await expect(adminLoginPage.backgroundElement).toHaveClass(/bg-gradient/);
  86. // 验证卡片阴影
  87. await expect(adminLoginPage.loginCard).toHaveClass(/shadow/);
  88. // 验证响应式设计
  89. await page.setViewportSize({ width: 375, height: 667 });
  90. await adminLoginPage.expectToBeVisible();
  91. // 移动端布局验证
  92. await expect(adminLoginPage.pageTitle).toBeVisible();
  93. await expect(adminLoginPage.usernameInput).toBeVisible();
  94. await expect(adminLoginPage.passwordInput).toBeVisible();
  95. });
  96. test('登录后刷新保持登录状态', async ({ adminLoginPage, dashboardPage, page }) => {
  97. // 先登录
  98. await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
  99. await dashboardPage.expectToBeVisible();
  100. // 刷新页面
  101. await page.reload();
  102. // 验证仍然保持登录状态
  103. await dashboardPage.expectToBeVisible();
  104. await expect(dashboardPage.pageTitle).toHaveText('仪表盘');
  105. });
  106. test('登出后重定向到登录页', async ({ adminLoginPage, dashboardPage, page }) => {
  107. // 先登录
  108. await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
  109. await dashboardPage.expectToBeVisible();
  110. // 执行登出
  111. await dashboardPage.logout();
  112. // 验证重定向到登录页
  113. await adminLoginPage.expectToBeVisible();
  114. await expect(adminLoginPage.pageTitle).toHaveText('管理后台登录');
  115. // 验证不能直接访问受保护页面
  116. await page.goto('/admin/dashboard');
  117. await adminLoginPage.expectToBeVisible(); // 应该重定向回登录页
  118. });
  119. test('多标签页登录状态同步', async ({ adminLoginPage, dashboardPage, context }) => {
  120. // 在第一个标签页登录
  121. await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
  122. await dashboardPage.expectToBeVisible();
  123. // 打开第二个标签页
  124. const newPage = await context.newPage();
  125. await newPage.goto('/admin/dashboard');
  126. // 验证第二个标签页也自动登录
  127. const newDashboardPage = dashboardPage.clone(newPage);
  128. await newDashboardPage.expectToBeVisible();
  129. // 在第一个标签页登出
  130. await dashboardPage.logout();
  131. await adminLoginPage.expectToBeVisible();
  132. // 验证第二个标签页也登出
  133. await newPage.reload();
  134. const newLoginPage = adminLoginPage.clone(newPage);
  135. await newLoginPage.expectToBeVisible();
  136. });
  137. test('登录加载状态显示', async ({ adminLoginPage }) => {
  138. // 填写登录信息
  139. await adminLoginPage.usernameInput.fill('admin');
  140. await adminLoginPage.passwordInput.fill('admin123');
  141. // 提交表单
  142. await adminLoginPage.submitButton.click();
  143. // 验证加载状态显示
  144. await expect(adminLoginPage.loadingSpinner).toBeVisible();
  145. await expect(adminLoginPage.submitButton).toBeDisabled();
  146. // 等待加载完成
  147. await expect(adminLoginPage.loadingSpinner).not.toBeVisible();
  148. });
  149. test('浏览器返回按钮行为', async ({ adminLoginPage, dashboardPage, page }) => {
  150. // 先登录
  151. await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
  152. await dashboardPage.expectToBeVisible();
  153. // 点击浏览器返回按钮
  154. await page.goBack();
  155. // 验证不会返回到登录页(应该停留在仪表盘或重定向)
  156. try {
  157. await adminLoginPage.expectToBeVisible({ timeout: 2000 });
  158. // 如果看到登录页,再次前进
  159. await page.goForward();
  160. await dashboardPage.expectToBeVisible();
  161. } catch {
  162. // 如果没看到登录页,说明行为正确
  163. await dashboardPage.expectToBeVisible();
  164. }
  165. });
  166. });