Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

130 рядки
6.5 KiB

  1. import { captureScreenshot, expect, test } from './fixtures'
  2. import { confirmMessageBox, loginAsAdmin, readAdminCredentials } from './helpers'
  3. // 认证用例会临时把真实凭据填入密码框。密码框本身不会进入成功截图,
  4. // 同时关闭 trace/video,避免失败制品保存表单快照。
  5. test.use({ trace: 'off', video: 'off' })
  6. const roleCases = [
  7. { code: 'administrative', label: '行政', accountLabel: '行政账号', organizationSelects: 1 },
  8. { code: 'teacher', label: '教员', accountLabel: '教员账号', organizationSelects: 2 },
  9. { code: 'student', label: '学员', accountLabel: '学员账号', organizationSelects: 0 },
  10. { code: 'admin', label: '管理员', accountLabel: '管理员账号', organizationSelects: 0 },
  11. ] as const
  12. test('登录页按行政、教员、学员、管理员展示真实身份控件', async ({ page }, testInfo) => {
  13. await page.goto('/login')
  14. await expect(page.getByRole('heading', { name: '登录数字人平台', exact: true })).toBeVisible()
  15. await expect(page.locator('.login-role-options > button')).toHaveCount(4)
  16. expect((await page.locator('.login-role-options > button').allTextContents()).map((item) => item.trim()))
  17. .toEqual(roleCases.map((item) => item.label))
  18. await expect(page.getByRole('button', { name: /登录系统/ })).toBeDisabled()
  19. await expect(page.getByText('管理员输入账号登录,其他身份请选择对应账号后输入密码。')).toBeVisible()
  20. for (const role of roleCases) {
  21. await test.step(`${role.label}身份控件`, async () => {
  22. await page.locator(`[data-role-code="${role.code}"]`).click()
  23. await expect(page.locator(`[data-role-code="${role.code}"]`)).toHaveAttribute('aria-pressed', 'true')
  24. await expect(page.locator('.login-role-fields')).toContainText(role.accountLabel)
  25. const username = page.locator('input[name="username"]')
  26. if (role.code === 'admin') {
  27. await expect(username).toBeVisible()
  28. await expect(username).toHaveAttribute('placeholder', '请输入管理员账号')
  29. await expect(page.locator('.login-role-fields .el-select')).toHaveCount(0)
  30. } else {
  31. await expect(username).toHaveCount(0)
  32. // 非管理员由“组织选择(如需要)+ 账号选择”组成,不允许手工输入账号。
  33. await expect(page.locator('.login-role-fields .el-select')).toHaveCount(role.organizationSelects + 1)
  34. await expect(page.locator('.login-identity-picker')).toBeVisible()
  35. }
  36. })
  37. }
  38. await page.locator('[data-role-code="admin"]').click()
  39. const password = page.locator('input[name="password"]')
  40. await expect(password).toHaveAttribute('type', 'password')
  41. await page.getByRole('button', { name: '显示密码' }).click()
  42. await expect(password).toHaveAttribute('type', 'text')
  43. await page.getByRole('button', { name: '隐藏密码' }).click()
  44. await expect(password).toHaveAttribute('type', 'password')
  45. await captureScreenshot(page, testInfo, 'login-four-identities')
  46. })
  47. test('错误密码被拒绝且不会建立登录会话', async ({ page }, testInfo) => {
  48. const credentials = readAdminCredentials()
  49. await page.goto('/login')
  50. await page.locator('[data-role-code="admin"]').click()
  51. await page.locator('input[name="username"]').fill(credentials.username)
  52. await page.locator('input[name="password"]').fill('APE2E-invalid-password-2026')
  53. await page.getByRole('button', { name: /登录系统/ }).click()
  54. await expect(page).toHaveURL(/\/login(?:\?|$)/)
  55. await expect(page.locator('#login-error')).not.toBeEmpty()
  56. await expect(page.locator('.app-shell')).toHaveCount(0)
  57. // 成功截图不保留任何账号或密码输入值。
  58. await page.locator('input[name="username"]').fill('')
  59. await page.locator('input[name="password"]').fill('')
  60. await captureScreenshot(page, testInfo, 'login-invalid-credential-rejected')
  61. })
  62. test('管理员可以登录、进入个人菜单并安全退出', async ({ page }, testInfo) => {
  63. await loginAsAdmin(page)
  64. await expect(page).toHaveURL(/\/overview(?:\?|$)/)
  65. await expect(page.locator('.app-shell')).toBeVisible()
  66. await expect(page.getByRole('heading', { name: '实时数字人智能体' })).toBeVisible()
  67. await expect(page.locator('input[name="password"]')).toHaveCount(0)
  68. await captureScreenshot(page, testInfo, 'admin-login-success')
  69. await page.locator('.user-menu-trigger').click()
  70. await expect(page.locator('#user-popover')).toBeVisible()
  71. await expect(page.getByRole('menuitem', { name: /个人中心/ })).toBeVisible()
  72. await expect(page.getByRole('menuitem', { name: /退出登录/ })).toBeVisible()
  73. await captureScreenshot(page, testInfo, 'admin-account-menu')
  74. await page.getByRole('menuitem', { name: /退出登录/ }).click()
  75. await confirmMessageBox(page, '退出登录')
  76. await expect(page).toHaveURL(/\/login(?:\?|$)/)
  77. await expect(page.getByRole('heading', { name: '登录数字人平台', exact: true })).toBeVisible()
  78. })
  79. test('兼容入口和未知地址重定向到正式路由', async ({ page }) => {
  80. await loginAsAdmin(page)
  81. const redirects = [
  82. { source: '/agents/hot-words', target: /\/knowledge\/hot-words(?:\?|$)/ },
  83. { source: '/studio?mode=offline', target: /\/videos\/create\?.*mode=offline/ },
  84. { source: '/works', target: /\/agents\/manage(?:\?|$)/ },
  85. { source: '/videos', target: /\/videos\/manage(?:\?|$)/ },
  86. { source: '/avatars', target: /\/assets\/avatars(?:\?|$)/ },
  87. { source: '/knowledge', target: /\/knowledge\/library(?:\?|$)/ },
  88. { source: '/operations/sensitive-words', target: /\/knowledge\/sensitive-words(?:\?|$)/ },
  89. { source: '/organization/structure', target: /\/organization\/departments(?:\?|$)/ },
  90. { source: '/change-password', target: /\/overview(?:\?|$)/ },
  91. { source: '/APE2E-route-does-not-exist', target: /\/overview(?:\?|$)/ },
  92. ]
  93. for (const item of redirects) {
  94. await test.step(item.source, async () => {
  95. await page.goto(item.source)
  96. await expect(page).toHaveURL(item.target)
  97. await expect(page.locator('.app-shell')).toBeVisible()
  98. })
  99. }
  100. await page.goto('/agents/create')
  101. await expect(page).toHaveURL(/\/agents\/manage\?.*create=1/)
  102. await expect(page.getByRole('dialog', { name: '新建智能体' })).toBeVisible()
  103. await page.getByRole('button', { name: '取消', exact: true }).click()
  104. })
  105. test('兼容入口 /studio 应能解析到实时智能体创建入口', async ({ page }) => {
  106. await loginAsAdmin(page)
  107. await page.goto('/studio')
  108. await expect(page).toHaveURL(/\/agents\/manage\?.*create=1/)
  109. await expect(page.getByRole('dialog', { name: '新建智能体' })).toBeVisible()
  110. })