Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 

92 righe
3.7 KiB

  1. import type { Page, Route } from '@playwright/test'
  2. import { captureScreenshot, expect, test } from './fixtures'
  3. test.use({ trace: 'off', video: 'off' })
  4. const loginContext = {
  5. defaultRoleCode: 'admin',
  6. roles: [
  7. { code: 'teacher', label: '教员', accountLabel: '教员账号', organizationMode: 'CASCADE', organizationLabels: ['教学系', '教研室'] },
  8. { code: 'admin', label: '管理员', accountLabel: '管理员账号', organizationMode: 'NONE', organizationLabels: [] },
  9. ],
  10. departments: [
  11. {
  12. id: '100', code: 'EQUIPMENT', name: '工程装备系', parentId: null,
  13. children: [{ id: '110', code: 'MAINTENANCE', name: '维修教研室', parentId: '100', children: [] }],
  14. },
  15. ],
  16. }
  17. const identities = [
  18. { id: '402', displayName: '杜晴', departmentId: '110', departmentName: '维修教研室' },
  19. ]
  20. const envelope = (data: unknown) => JSON.stringify({
  21. code: 200,
  22. message: '成功',
  23. data,
  24. timestamp: '2026-08-29T12:00:00+08:00',
  25. requestId: 'ape2e-login-identity-preference',
  26. })
  27. const fulfill = (route: Route, data: unknown) => route.fulfill({
  28. status: 200,
  29. contentType: 'application/json',
  30. body: envelope(data),
  31. })
  32. async function mockLoginDependencies(page: Page) {
  33. await page.route('**/api/auth/v1/**', async (route) => {
  34. const path = new URL(route.request().url()).pathname
  35. if (path.endsWith('/auth/login-context')) return fulfill(route, loginContext)
  36. if (path.endsWith('/auth/login-identities')) return fulfill(route, identities)
  37. if (path.endsWith('/system-config/public')) return fulfill(route, {})
  38. return fulfill(route, {})
  39. })
  40. }
  41. test('登录页恢复上次成功登录的部门和账号但不保存密码', async ({ page }, testInfo) => {
  42. await page.addInitScript(() => {
  43. window.localStorage.setItem('ai-person:web:login-identity-preference:v1', JSON.stringify({
  44. lastRoleCode: 'teacher',
  45. selections: {
  46. teacher: { departmentId: '110', userId: '402', username: '' },
  47. },
  48. }))
  49. })
  50. await mockLoginDependencies(page)
  51. await page.goto('/login')
  52. await expect(page.locator('[data-role-code="teacher"]')).toHaveAttribute('aria-pressed', 'true')
  53. const organizationSelects = page.locator('.login-role-fields .login-picker:not(.login-identity-picker)')
  54. await expect(organizationSelects.nth(0)).toContainText('工程装备系')
  55. await expect(organizationSelects.nth(1)).toContainText('维修教研室')
  56. await expect(page.locator('.login-identity-picker')).toContainText('杜晴')
  57. await expect(page.locator('input[name="password"]')).toHaveValue('')
  58. await expect(page.getByRole('button', { name: '登录' })).toBeDisabled()
  59. await captureScreenshot(page, testInfo, 'restored-login-identity-without-password')
  60. })
  61. test('已删除的部门或账号不会被本地偏好错误回填', async ({ page }) => {
  62. await page.addInitScript(() => {
  63. window.localStorage.setItem('ai-person:web:login-identity-preference:v1', JSON.stringify({
  64. lastRoleCode: 'teacher',
  65. selections: {
  66. teacher: { departmentId: '999', userId: '999', username: '' },
  67. },
  68. }))
  69. })
  70. await mockLoginDependencies(page)
  71. await page.goto('/login')
  72. await expect(page.locator('[data-role-code="teacher"]')).toHaveAttribute('aria-pressed', 'true')
  73. const organizationSelects = page.locator('.login-role-fields .login-picker:not(.login-identity-picker)')
  74. await expect(organizationSelects.nth(0).locator('.el-select__placeholder').first()).toContainText('请选择教学系')
  75. await expect(organizationSelects.nth(1).getByRole('combobox')).toBeDisabled()
  76. await expect(page.locator('.login-identity-picker').getByRole('combobox')).toBeDisabled()
  77. await expect(page.locator('input[name="password"]')).toHaveValue('')
  78. })