import { expect, test } from './fixtures'; import { decodeJwtPayload, detectOrgSelectState, extractOrgIdFromTokenPayload, resolveOrgContextForCoursePage, establishSession, waitForCourseRealmVisible, } from './helpers/music-room-session'; const moicenUnionid = process.env.MOICEN_E2E_UNIONID?.trim(); test.describe('多机构数据隔离(会话与 token)', () => { test.describe.configure({ timeout: 180_000 }); test.skip(!moicenUnionid, '需要 MOICEN_E2E_UNIONID(Secret 或 .env.e2e)'); test('本地 CurrentOrgId 与 JWT current_org_id 一致', async ({ page }) => { await establishSession(page, moicenUnionid!); if ( await page.getByText('请返回微信小程序完成登录').isVisible().catch(() => false) ) { test.skip(true, '当前 unionid 会话未处于可用登录态'); } await resolveOrgContextForCoursePage(page); const storage = await page.evaluate(() => ({ currentOrgId: window.localStorage.getItem('CurrentOrgId'), authorization: window.localStorage.getItem('Authorization'), })); expect(storage.authorization, '登录后应有 Authorization').toBeTruthy(); const payload = decodeJwtPayload(storage.authorization!); expect(payload, 'Authorization 应为可解析的 JWT').not.toBeNull(); const jwtOrgId = extractOrgIdFromTokenPayload(payload); expect(jwtOrgId, 'JWT(含 sub 嵌套)应能解析出 current_org_id').toBeTruthy(); if (storage.currentOrgId) { expect(storage.currentOrgId).toBe(jwtOrgId); } }); test('机构选择页存在多个机构时,切换后 CurrentOrgId 变化', async ({ page, }) => { await establishSession(page, moicenUnionid!); if ( await page.getByText('请返回微信小程序完成登录').isVisible().catch(() => false) ) { test.skip(true, '当前 unionid 会话未处于可用登录态'); } await resolveOrgContextForCoursePage(page); await page.goto('/org/select', { waitUntil: 'load', timeout: 90_000, }); await expect(page.locator('#app')).toBeVisible({ timeout: 90_000 }); await page.waitForURL(/\/org\/select/, { timeout: 90_000 }); if ( await page.getByText('请返回微信小程序完成登录').isVisible().catch(() => false) ) { test.skip(true, '打开机构页时会话已退回访客态'); } const orgSelectState = await detectOrgSelectState(page, 90_000); if (orgSelectState === 'guest') { test.skip(true, '打开机构页时会话已退回访客态'); } if (orgSelectState === 'timeout') { test.skip(true, `机构页未渲染可识别结构:${page.url()}`); } if ( await page.getByText('暂无可用机构').isVisible().catch(() => false) ) { test.skip(true, '机构接口无数据,跳过多机构切换断言'); } const orgCells = page.locator('#app .van-cell-group .van-cell'); const count = await orgCells.count(); test.skip( count < 2, '账号仅绑定单一机构时跳过切换断言(仍可通过 JWT 对齐用例校验隔离键)' ); let beforeOrg: string | null = await page.evaluate(() => window.localStorage.getItem('CurrentOrgId') ); if (!beforeOrg) { const authSnap = await page.evaluate(() => window.localStorage.getItem('Authorization') ); beforeOrg = extractOrgIdFromTokenPayload( decodeJwtPayload(authSnap ?? '') ) ?? null; } expect(beforeOrg, '切换前应能从 localStorage 或 JWT 解析当前机构').toBeTruthy(); await orgCells.nth(1).click(); await page.waitForURL( (u) => { try { return new URL(u).pathname === '/' || new URL(u).pathname === ''; } catch { return false; } }, { timeout: 90_000 } ); await expect(page.locator('#app')).toBeVisible({ timeout: 90_000 }); const afterOrg = await page.evaluate(() => window.localStorage.getItem('CurrentOrgId') ); expect(afterOrg).toBeTruthy(); expect(afterOrg).not.toBe(beforeOrg); const authAfter = await page.evaluate(() => window.localStorage.getItem('Authorization') ); const payloadAfter = decodeJwtPayload(authAfter ?? ''); const jwtOrgAfter = extractOrgIdFromTokenPayload(payloadAfter); expect(jwtOrgAfter, '切换后 JWT 应携带 current_org_id').toBeTruthy(); expect(jwtOrgAfter).toBe(afterOrg); }); test('课程体系页加载成功且不进入列表错误态(机构维度接口可用)', async ({ page, }) => { await establishSession(page, moicenUnionid!); if ( await page.getByText('请返回微信小程序完成登录').isVisible().catch(() => false) ) { test.skip(true, '当前 unionid 会话未处于可用登录态'); } await resolveOrgContextForCoursePage(page); await page.goto('/course', { waitUntil: 'domcontentloaded', timeout: 90_000, }); await expect(page.locator('#app')).toBeVisible({ timeout: 90_000 }); await waitForCourseRealmVisible(page); const listError = page.getByText('请求失败,点击重新加载'); await expect(listError).toHaveCount(0, { timeout: 45_000, }); }); });