| @@ -0,0 +1,91 @@ | |||
| import type { Page, Route } from '@playwright/test' | |||
| import { captureScreenshot, expect, test } from './fixtures' | |||
| test.use({ trace: 'off', video: 'off' }) | |||
| const loginContext = { | |||
| defaultRoleCode: 'admin', | |||
| roles: [ | |||
| { code: 'teacher', label: '教员', accountLabel: '教员账号', organizationMode: 'CASCADE', organizationLabels: ['教学系', '教研室'] }, | |||
| { code: 'admin', label: '管理员', accountLabel: '管理员账号', organizationMode: 'NONE', organizationLabels: [] }, | |||
| ], | |||
| departments: [ | |||
| { | |||
| id: '100', code: 'EQUIPMENT', name: '工程装备系', parentId: null, | |||
| children: [{ id: '110', code: 'MAINTENANCE', name: '维修教研室', parentId: '100', children: [] }], | |||
| }, | |||
| ], | |||
| } | |||
| const identities = [ | |||
| { id: '402', displayName: '杜晴', departmentId: '110', departmentName: '维修教研室' }, | |||
| ] | |||
| const envelope = (data: unknown) => JSON.stringify({ | |||
| code: 200, | |||
| message: '成功', | |||
| data, | |||
| timestamp: '2026-08-29T12:00:00+08:00', | |||
| requestId: 'ape2e-login-identity-preference', | |||
| }) | |||
| const fulfill = (route: Route, data: unknown) => route.fulfill({ | |||
| status: 200, | |||
| contentType: 'application/json', | |||
| body: envelope(data), | |||
| }) | |||
| async function mockLoginDependencies(page: Page) { | |||
| await page.route('**/api/auth/v1/**', async (route) => { | |||
| const path = new URL(route.request().url()).pathname | |||
| if (path.endsWith('/auth/login-context')) return fulfill(route, loginContext) | |||
| if (path.endsWith('/auth/login-identities')) return fulfill(route, identities) | |||
| if (path.endsWith('/system-config/public')) return fulfill(route, {}) | |||
| return fulfill(route, {}) | |||
| }) | |||
| } | |||
| test('登录页恢复上次成功登录的部门和账号但不保存密码', async ({ page }, testInfo) => { | |||
| await page.addInitScript(() => { | |||
| window.localStorage.setItem('ai-person:web:login-identity-preference:v1', JSON.stringify({ | |||
| lastRoleCode: 'teacher', | |||
| selections: { | |||
| teacher: { departmentId: '110', userId: '402', username: '' }, | |||
| }, | |||
| })) | |||
| }) | |||
| await mockLoginDependencies(page) | |||
| await page.goto('/login') | |||
| await expect(page.locator('[data-role-code="teacher"]')).toHaveAttribute('aria-pressed', 'true') | |||
| const organizationSelects = page.locator('.login-role-fields .login-picker:not(.login-identity-picker)') | |||
| await expect(organizationSelects.nth(0)).toContainText('工程装备系') | |||
| await expect(organizationSelects.nth(1)).toContainText('维修教研室') | |||
| await expect(page.locator('.login-identity-picker')).toContainText('杜晴') | |||
| await expect(page.locator('input[name="password"]')).toHaveValue('') | |||
| await expect(page.getByRole('button', { name: '登录' })).toBeDisabled() | |||
| await captureScreenshot(page, testInfo, 'restored-login-identity-without-password') | |||
| }) | |||
| test('已删除的部门或账号不会被本地偏好错误回填', async ({ page }) => { | |||
| await page.addInitScript(() => { | |||
| window.localStorage.setItem('ai-person:web:login-identity-preference:v1', JSON.stringify({ | |||
| lastRoleCode: 'teacher', | |||
| selections: { | |||
| teacher: { departmentId: '999', userId: '999', username: '' }, | |||
| }, | |||
| })) | |||
| }) | |||
| await mockLoginDependencies(page) | |||
| await page.goto('/login') | |||
| await expect(page.locator('[data-role-code="teacher"]')).toHaveAttribute('aria-pressed', 'true') | |||
| const organizationSelects = page.locator('.login-role-fields .login-picker:not(.login-identity-picker)') | |||
| await expect(organizationSelects.nth(0).locator('.el-select__placeholder').first()).toContainText('请选择教学系') | |||
| await expect(organizationSelects.nth(1).getByRole('combobox')).toBeDisabled() | |||
| await expect(page.locator('.login-identity-picker').getByRole('combobox')).toBeDisabled() | |||
| await expect(page.locator('input[name="password"]')).toHaveValue('') | |||
| }) | |||