fix(e2e): JWT sub 内嵌 current_org_id;深链 /course 重试直至落地
Made-with: Cursor
This commit is contained in:
@@ -16,6 +16,25 @@ function decodeJwtPayload(token: string): Record<string, unknown> | null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 与 `huike-front/src/main.ts` 中 `parseCurrentOrgIdFromToken` 一致:claims 可能在顶层或嵌在 `sub` JSON 内 */
|
||||||
|
function extractOrgIdFromTokenPayload(
|
||||||
|
payload: Record<string, unknown> | null
|
||||||
|
): string | undefined {
|
||||||
|
if (!payload) return undefined;
|
||||||
|
const top = payload.current_org_id;
|
||||||
|
if (typeof top === 'string' && top.length > 0) return top;
|
||||||
|
const sub = payload.sub;
|
||||||
|
if (typeof sub !== 'string' || sub.length === 0) return undefined;
|
||||||
|
try {
|
||||||
|
const inner = JSON.parse(sub) as Record<string, unknown>;
|
||||||
|
const innerOrg = inner.current_org_id;
|
||||||
|
if (typeof innerOrg === 'string' && innerOrg.length > 0) return innerOrg;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
async function establishSession(page: Page) {
|
async function establishSession(page: Page) {
|
||||||
const q = new URLSearchParams({
|
const q = new URLSearchParams({
|
||||||
unionid: moicenUnionid!,
|
unionid: moicenUnionid!,
|
||||||
@@ -48,11 +67,10 @@ async function resolveOrgContextForCoursePage(page: Page) {
|
|||||||
});
|
});
|
||||||
await expect(page.locator('#app')).toBeVisible({ timeout: 90_000 });
|
await expect(page.locator('#app')).toBeVisible({ timeout: 90_000 });
|
||||||
|
|
||||||
if (!page.url().includes('/org/select')) {
|
if (page.url().includes('/org/select')) {
|
||||||
return;
|
await expect(page.locator('.main h4')).toContainText(/请选择机构/, {
|
||||||
}
|
timeout: 60_000,
|
||||||
|
});
|
||||||
await expect(page.getByText('请选择机构')).toBeVisible({ timeout: 60_000 });
|
|
||||||
await Promise.race([
|
await Promise.race([
|
||||||
page
|
page
|
||||||
.locator('.main .van-cell-group .van-cell')
|
.locator('.main .van-cell-group .van-cell')
|
||||||
@@ -74,9 +92,19 @@ async function resolveOrgContextForCoursePage(page: Page) {
|
|||||||
expect(n, '机构选择页应有可选机构').toBeGreaterThan(0);
|
expect(n, '机构选择页应有可选机构').toBeGreaterThan(0);
|
||||||
await pickCells.first().click();
|
await pickCells.first().click();
|
||||||
await expect(page.locator('#app')).toBeVisible({ timeout: 90_000 });
|
await expect(page.locator('#app')).toBeVisible({ timeout: 90_000 });
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('resolveOrgContextForCoursePage: 无法在合理步数内离开机构选择页');
|
if (page.url().includes('/course')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 守卫可能暂时送回首页「进入工作台」等,下一循环再深链 `/course`
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
'resolveOrgContextForCoursePage: 无法在合理步数内进入 /course(可能被重定向离开课程体系)'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
test.describe('多机构数据隔离(会话与 token)', () => {
|
test.describe('多机构数据隔离(会话与 token)', () => {
|
||||||
@@ -100,10 +128,10 @@ test.describe('多机构数据隔离(会话与 token)', () => {
|
|||||||
|
|
||||||
const payload = decodeJwtPayload(storage.authorization!);
|
const payload = decodeJwtPayload(storage.authorization!);
|
||||||
expect(payload, 'Authorization 应为可解析的 JWT').not.toBeNull();
|
expect(payload, 'Authorization 应为可解析的 JWT').not.toBeNull();
|
||||||
const jwtOrgId = payload!.current_org_id;
|
const jwtOrgId = extractOrgIdFromTokenPayload(payload);
|
||||||
expect(jwtOrgId, 'JWT 应包含 current_org_id').toBeTruthy();
|
expect(jwtOrgId, 'JWT(含 sub 嵌套)应能解析出 current_org_id').toBeTruthy();
|
||||||
expect(storage.currentOrgId, '进入业务路由后应写入 CurrentOrgId').toBeTruthy();
|
expect(storage.currentOrgId, '进入业务路由后应写入 CurrentOrgId').toBeTruthy();
|
||||||
expect(String(jwtOrgId)).toBe(storage.currentOrgId);
|
expect(jwtOrgId).toBe(storage.currentOrgId);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('机构选择页存在多个机构时,切换后 CurrentOrgId 变化', async ({
|
test('机构选择页存在多个机构时,切换后 CurrentOrgId 变化', async ({
|
||||||
@@ -123,7 +151,8 @@ test.describe('多机构数据隔离(会话与 token)', () => {
|
|||||||
timeout: 60_000,
|
timeout: 60_000,
|
||||||
});
|
});
|
||||||
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||||
await expect(page.getByText('请选择机构')).toBeVisible({
|
await page.waitForURL(/\/org\/select/, { timeout: 60_000 });
|
||||||
|
await expect(page.locator('.main h4')).toContainText(/请选择机构/, {
|
||||||
timeout: 60_000,
|
timeout: 60_000,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -165,8 +194,9 @@ test.describe('多机构数据隔离(会话与 token)', () => {
|
|||||||
window.localStorage.getItem('Authorization')
|
window.localStorage.getItem('Authorization')
|
||||||
);
|
);
|
||||||
const payloadAfter = decodeJwtPayload(authAfter ?? '');
|
const payloadAfter = decodeJwtPayload(authAfter ?? '');
|
||||||
expect(payloadAfter?.current_org_id).toBeTruthy();
|
const jwtOrgAfter = extractOrgIdFromTokenPayload(payloadAfter);
|
||||||
expect(String(payloadAfter!.current_org_id)).toBe(afterOrg);
|
expect(jwtOrgAfter, '切换后 JWT 应携带 current_org_id').toBeTruthy();
|
||||||
|
expect(jwtOrgAfter).toBe(afterOrg);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('课程体系页加载成功且不进入列表错误态(机构维度接口可用)', async ({
|
test('课程体系页加载成功且不进入列表错误态(机构维度接口可用)', async ({
|
||||||
|
|||||||
Reference in New Issue
Block a user