admin-panel.spec.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /**
  2. * ================================================================
  3. * 场景:后台管理全流程 E2E 测试
  4. * ================================================================
  5. * 目标:管理员通过 cfc-web Element UI 管理后台进行用户管理、数据看板等
  6. * 部署地址:http://cfc.iwintrue.com
  7. *
  8. * 流程步骤:
  9. * 1. 管理员查看用户列表
  10. * 2. 管理员查看数据看板
  11. * 3. 能量规则管理
  12. * 4. 系统健康检查
  13. *
  14. * 前置条件:已登录管理员账号
  15. * ================================================================
  16. */
  17. const { test, expect } = require('@playwright/test');
  18. /**
  19. * 确保已登录到管理后台
  20. * 尝试多种可能的登录表单选择器,加长超时处理 Vue SPA 渲染
  21. */
  22. async function ensureLoggedIn(page) {
  23. // 先检查是否已登录(侧边栏可见)
  24. const sidebar = page.locator('.sidebar-container, .el-menu-vertical-demo, .el-aside, #app > div');
  25. try {
  26. await sidebar.waitFor({ state: 'visible', timeout: 5000 });
  27. return;
  28. } catch {
  29. // 未登录,继续登录流程
  30. }
  31. // 跳转到登录页,等待完整加载
  32. await page.goto('/admin/login', { waitUntil: 'networkidle', timeout: 30000 });
  33. // 额外等待 Vue 渲染完成
  34. await page.waitForTimeout(2000);
  35. // 截图保留现场(调试用)
  36. await page.screenshot({ path: 'test-artifacts/login-page.png' }).catch(() => {});
  37. // 尝试多种输入框选择器(Element UI 版本差异)
  38. const inputSelectors = [
  39. '.el-input__inner',
  40. 'input[type="text"]',
  41. 'input[placeholder*="账号"]',
  42. 'input[placeholder*="用户名"]',
  43. 'input[name="username"]',
  44. '.el-input input',
  45. ];
  46. let inputFound = false;
  47. for (const sel of inputSelectors) {
  48. try {
  49. const el = page.locator(sel).first();
  50. if (await el.isVisible({ timeout: 3000 })) {
  51. await el.fill('admin');
  52. inputFound = true;
  53. break;
  54. }
  55. } catch {
  56. // 继续尝试下一个选择器
  57. }
  58. }
  59. if (!inputFound) {
  60. // 兜底:直接填写可见的第一个输入框
  61. const allInputs = page.locator('input');
  62. const count = await allInputs.count();
  63. if (count > 0) {
  64. await allInputs.first().fill('admin');
  65. if (count > 1) {
  66. await allInputs.nth(1).fill('admin123');
  67. }
  68. }
  69. }
  70. // 填写密码
  71. const pwdInputs = page.locator('input[type="password"]');
  72. if (await pwdInputs.count() > 0) {
  73. await pwdInputs.first().fill('admin123');
  74. } else {
  75. // 尝试按位置填写第二个输入框
  76. const allInputs = page.locator('input');
  77. const count = await allInputs.count();
  78. if (count >= 2) {
  79. await allInputs.nth(1).fill('admin123');
  80. }
  81. }
  82. // 尝试点击登录按钮
  83. const btnSelectors = [
  84. '.el-button--primary',
  85. 'button[type="submit"]',
  86. '.login-btn',
  87. '.el-button:has-text("登录")',
  88. '.el-button:has-text("登 录")',
  89. ];
  90. for (const sel of btnSelectors) {
  91. try {
  92. const btn = page.locator(sel).first();
  93. if (await btn.isVisible({ timeout: 2000 })) {
  94. await btn.click();
  95. break;
  96. }
  97. } catch {
  98. // 继续尝试
  99. }
  100. }
  101. // 等待登录完成(dashboard 或侧边栏出现)
  102. try {
  103. await page.waitForURL(/\/dashboard|\/admin\//, { timeout: 20000 });
  104. } catch {
  105. // 可能 URL 没变但页面已登录,等待侧边栏出现
  106. await page.waitForSelector('.sidebar-container, .el-menu, .el-aside', { timeout: 15000 });
  107. }
  108. }
  109. test.describe('【场景流程】后台管理全流程', () => {
  110. test('[场景1] 管理员查看用户列表 - 期望返回分页列表', async ({ page }) => {
  111. await ensureLoggedIn(page);
  112. await page.goto('/users', { waitUntil: 'networkidle' });
  113. await page.waitForTimeout(2000);
  114. await page.screenshot({ path: 'test-artifacts/admin-users.png' }).catch(() => {});
  115. // 尝试多种表格选择器
  116. const table = page.locator('.el-table, .el-table__body, table, .el-table__header');
  117. await expect(table.first()).toBeVisible({ timeout: 15000 });
  118. });
  119. test('[场景2] 管理员查看数据看板 - 期望返回统计数据', async ({ page }) => {
  120. await ensureLoggedIn(page);
  121. await page.goto('/dashboard', { waitUntil: 'networkidle' });
  122. await page.waitForTimeout(2000);
  123. await page.screenshot({ path: 'test-artifacts/admin-dashboard.png' }).catch(() => {});
  124. // 检查是否有统计卡片或内容区域
  125. const content = page.locator('.el-card, .dashboard-container, .app-container, .el-main');
  126. await expect(content.first()).toBeVisible({ timeout: 15000 });
  127. });
  128. test('[场景3] 管理员查看能量规则管理', async ({ page }) => {
  129. await ensureLoggedIn(page);
  130. await page.goto('/energy-rule', { waitUntil: 'networkidle' });
  131. await page.waitForTimeout(2000);
  132. await page.screenshot({ path: 'test-artifacts/admin-energy-rule.png' }).catch(() => {});
  133. // 检查是否有表格或内容
  134. const table = page.locator('.el-table, .el-form, .app-container');
  135. await expect(table.first()).toBeVisible({ timeout: 15000 });
  136. });
  137. test('[场景4] 系统健康检查 - 期望返回健康状态', async ({ page }) => {
  138. await ensureLoggedIn(page);
  139. await page.goto('/sys-config', { waitUntil: 'networkidle' });
  140. await page.waitForTimeout(2000);
  141. await page.screenshot({ path: 'test-artifacts/admin-sys-config.png' }).catch(() => {});
  142. // 检查配置页面是否加载
  143. const content = page.locator('.el-card, .app-container, .el-form, .sys-config-page');
  144. await expect(content.first()).toBeVisible({ timeout: 15000 });
  145. });
  146. });