import { expect, test } from './fixtures'; /** * 部门默认透明测试 * * 测试 CI unionid 测试用户,其所有机构都只有 1 个 active 部门(默认部门), * 因此前端不应出现部门选择入口: * - localStorage 自动写入 CurrentDepartmentId * - 页面路径不包含 department 参数 * - 角色选择、排课列表、课包商店等已有页面不受影响 * * 注意:CI 用户可能有多机构,需要先选机构,再触发部门自动选中。 */ const moicenUnionid = process.env.MOICEN_E2E_UNIONID?.trim(); /** * 登录 → 依次处理机构选择 + 身份选择 → 到达首页 * 适用于多机构用户的场景 */ async function loginAndDismissSelectors(page: any) { const q = new URLSearchParams({ unionid: moicenUnionid!, status: '2' }); await page.goto(`/?${q.toString()}`, { waitUntil: 'domcontentloaded', timeout: 60_000, }); await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 }); // 等待 auth tokens await expect(async () => { const auth = await page.evaluate(() => window.localStorage.getItem('Authorization') ); expect(auth).toBeTruthy(); }).toPass({ timeout: 30_000 }); // 逐层处理选择页:机构选择 → 身份选择(可能有 0~n 层) for (let i = 0; i < 5; i++) { const path = await page.evaluate(() => window.location.pathname); console.log(`[DeptTest] iteration ${i}: path=${path}`); console.log(`[DeptTest] has Authorization:`, !!await page.evaluate(() => window.localStorage.getItem('Authorization'))); console.log(`[DeptTest] has HtySudoerToken:`, !!await page.evaluate(() => window.localStorage.getItem('HtySudoerToken'))); if (path === '/org/select') { await page.locator('.van-cell').first().click(); console.log('[DeptTest] clicked org cell'); await page.waitForTimeout(3_000); } else if (path === '/') { const rs = page.getByText('请选择您的登录身份'); if (await rs.isVisible().catch(() => false)) { await page.locator('.van-grid-item').first().click(); console.log('[DeptTest] clicked role'); await page.waitForTimeout(3_000); } else { console.log('[DeptTest] at / but no role selector, break'); break; } } else { console.log('[DeptTest] unexpected path, break'); break; } } } test.describe('单部门透明', () => { test.skip(!moicenUnionid, '需要 MOICEN_E2E_UNIONID(Secret 或 .env.e2e)'); function decodeJwtPayloadCompact(token: string): Record { const parts = token.split('.'); if (parts.length < 2) return {}; const raw = parts[1].replace(/-/g, '+').replace(/_/g, '/'); const padded = raw.padEnd(Math.ceil(raw.length / 4) * 4, '='); const decoded = decodeURIComponent( atob(padded) .split('') .map(c => `%${(`00${c.charCodeAt(0).toString(16)}`).slice(-2)}`) .join('') ); return JSON.parse(decoded); } test('自动选中默认部门,不出现部门选择 UI', async ({ page }) => { test.setTimeout(180_000); await loginAndDismissSelectors(page); // 检查登录后的 JWT const loginJwt = await page.evaluate(() => window.localStorage.getItem('Authorization')); if (loginJwt) { const payload = decodeJwtPayloadCompact(loginJwt); let sub: Record = {}; if (typeof payload.sub === 'string') sub = JSON.parse(payload.sub); console.log('[DeptTest JWT before] top-level keys:', Object.keys(payload)); console.log('[DeptTest JWT before] payload.current_org_id:', payload.current_org_id); console.log('[DeptTest JWT before] sub.current_org_id:', (sub as any).current_org_id); console.log('[DeptTest JWT before] sub.current_department_id:', (sub as any).current_department_id); } // 导航到排课页触发路由守卫中的 org 加载 + 部门自动选中 await page.goto('/clazz', { waitUntil: 'networkidle', timeout: 90_000, }); await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 }); // 打印当前页面状态 const pageState = await page.evaluate(() => { const ls = (k: string) => window.localStorage.getItem(k); return { pathname: window.location.pathname, CurrentOrgId: ls('CurrentOrgId'), CurrentDepartmentId: ls('CurrentDepartmentId'), hasAuth: !!ls('Authorization'), hasSudo: !!ls('HtySudoerToken'), guardError: ls('__guardError'), orgSwitchDebug: ls('OrgSwitchDebug'), }; }); console.log('[DeptTest] state after goto:', JSON.stringify(pageState, null, 2)); // 验证 localStorage 写入了 CurrentDepartmentId const deptId = pageState.CurrentDepartmentId; expect(deptId).toBeTruthy(); expect(deptId).toContain('dept_default_'); // 验证页面路径不包含 department 相关参数 expect(pageState.pathname).not.toContain('department'); // 验证 token 中包含 department_id const authToken = await page.evaluate(() => window.localStorage.getItem('Authorization') ); expect(authToken).toBeTruthy(); if (authToken) { const parts = authToken.split('.'); expect(parts.length).toBe(3); const payloadRaw = parts[1].replace(/-/g, '+').replace(/_/g, '/'); const payload = JSON.parse(atob(payloadRaw)); console.log('[JWT Debug] top-level keys:', Object.keys(payload)); console.log('[JWT Debug] payload.current_department_id:', payload.current_department_id); console.log('[JWT Debug] payload.current_org_id:', payload.current_org_id); let subjectPayload: Record = {}; if (typeof payload.sub === 'string') { subjectPayload = JSON.parse(payload.sub); console.log('[JWT Debug] sub keys:', Object.keys(subjectPayload)); console.log('[JWT Debug] sub.current_department_id:', subjectPayload.current_department_id); console.log('[JWT Debug] sub.current_org_id:', subjectPayload.current_org_id); console.log('[JWT Debug] sub.current_org_id type:', typeof subjectPayload.current_org_id); } const deptIdInJwt = payload.current_department_id || subjectPayload.current_department_id; expect(deptIdInJwt).toBeTruthy(); expect(typeof deptIdInJwt).toBe('string'); } }); test('已有部门上下文时不重复加载部门列表', async ({ page }) => { await loginAndDismissSelectors(page); // 导航到排课页触发 org 加载 + 部门自动选中,验证页面正常渲染 await page.goto('/clazz', { waitUntil: 'domcontentloaded', timeout: 60_000, }); await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 }); }); });