fix(e2e): 交替深链 /course/summary 与 /course;移除 networkidle;扩充壳层与超时

Made-with: Cursor
This commit is contained in:
2026-04-28 10:04:19 +08:00
parent 3428204659
commit 4e970f3a50
+30 -17
View File
@@ -38,26 +38,32 @@ function extractOrgIdFromTokenPayload(
/** /**
* 教学资源相关任意壳层可见即可(`/course/summary` 入口链或课程体系列表)。 * 教学资源相关任意壳层可见即可(`/course/summary` 入口链或课程体系列表)。
* CI 上课程索引偶发长时间无搜索框;summary 页 Cell 更稳定 * CI 上 SPA 长连接会导致 networkidle 不可靠;此处只用 DOM 信号轮询
*/ */
async function waitForCourseRealmVisible(page: Page) { async function waitForCourseRealmVisible(page: Page) {
const deadline = Date.now() + 95_000; const deadline = Date.now() + 95_000;
while (Date.now() < deadline) { while (Date.now() < deadline) {
const titleHit = await page.title().catch(() => '');
if (/教学资源库|课程体系/.test(titleHit)) {
return;
}
if ( if (
await page.getByRole('link', { name: '课程体系' }).isVisible().catch(() => false) await page.getByRole('link', { name: '课程体系' }).isVisible().catch(() => false)
) { ) {
return; return;
} }
for (const label of ['课程体系', '课程', '课节']) {
if ( if (
await page await page
.locator('.van-cell') .locator('.van-cell')
.filter({ hasText: /课程体系/ }) .filter({ hasText: new RegExp(label) })
.first() .first()
.isVisible() .isVisible()
.catch(() => false) .catch(() => false)
) { ) {
return; return;
} }
}
if ( if (
await page await page
.getByPlaceholder('请输入课程体系名称搜索') .getByPlaceholder('请输入课程体系名称搜索')
@@ -73,9 +79,7 @@ async function waitForCourseRealmVisible(page: Page) {
} }
await page.waitForTimeout(400); await page.waitForTimeout(400);
} }
throw new Error( throw new Error(`教学资源壳层未出现:${page.url()}`);
`教学资源壳层未出现:${page.url()}`
);
} }
async function establishSession(page: Page) { async function establishSession(page: Page) {
@@ -100,11 +104,15 @@ async function establishSession(page: Page) {
/** /**
* 停留在 `/` 时 main.ts 不会把 JWT 中的机构写入 CurrentOrgId。 * 停留在 `/` 时 main.ts 不会把 JWT 中的机构写入 CurrentOrgId。
* 深链到 `/course` 会触发守卫;多机构且无上下文时会先进入 `/org/select`,需点选机构后再继续。 * 深链会触发守卫;多机构且无上下文时会先进入 `/org/select`,需点选机构后再继续。
* 交替尝试 summary 与课程索引:部分账号在 CI 上只对其中之一稳定渲染壳层。
*/ */
async function resolveOrgContextForCoursePage(page: Page) { async function resolveOrgContextForCoursePage(page: Page) {
for (let attempt = 0; attempt < 6; attempt++) { const deepPaths = ['/course/summary', '/course'] as const;
await page.goto('/course/summary', {
for (let attempt = 0; attempt < 8; attempt++) {
const targetPath = deepPaths[attempt % deepPaths.length];
await page.goto(targetPath, {
waitUntil: 'domcontentloaded', waitUntil: 'domcontentloaded',
timeout: 90_000, timeout: 90_000,
}); });
@@ -138,14 +146,17 @@ async function resolveOrgContextForCoursePage(page: Page) {
continue; continue;
} }
if ( try {
page.url().includes('/course/summary') || const path = new URL(page.url()).pathname || '';
page.url().includes('/course') const onCourseRealm =
) { path === '/course' || path.startsWith('/course/');
await page.waitForLoadState('networkidle', { timeout: 60_000 }).catch(() => {}); if (onCourseRealm) {
await waitForCourseRealmVisible(page); await waitForCourseRealmVisible(page);
return; return;
} }
} catch {
/* URL 解析失败则继续重试 */
}
// 守卫可能暂时送回首页「进入工作台」等,下一循环再深链 // 守卫可能暂时送回首页「进入工作台」等,下一循环再深链
} }
@@ -156,6 +167,8 @@ async function resolveOrgContextForCoursePage(page: Page) {
} }
test.describe('多机构数据隔离(会话与 token', () => { test.describe('多机构数据隔离(会话与 token', () => {
test.describe.configure({ timeout: 180_000 });
test.skip(!moicenUnionid, '需要 MOICEN_E2E_UNIONIDSecret 或 .env.e2e'); test.skip(!moicenUnionid, '需要 MOICEN_E2E_UNIONIDSecret 或 .env.e2e');
test('本地 CurrentOrgId 与 JWT current_org_id 一致', async ({ page }) => { test('本地 CurrentOrgId 与 JWT current_org_id 一致', async ({ page }) => {
@@ -201,7 +214,6 @@ test.describe('多机构数据隔离(会话与 token', () => {
}); });
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 }); await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
await page.waitForURL(/\/org\/select/, { timeout: 60_000 }); await page.waitForURL(/\/org\/select/, { timeout: 60_000 });
await page.waitForLoadState('networkidle', { timeout: 60_000 }).catch(() => {});
await expect(page.getByText(/请选择机构|选择机构/)).toBeVisible({ await expect(page.getByText(/请选择机构|选择机构/)).toBeVisible({
timeout: 60_000, timeout: 60_000,
}); });
@@ -274,8 +286,9 @@ test.describe('多机构数据隔离(会话与 token', () => {
await expect(page.locator('#app')).toBeVisible({ timeout: 90_000 }); await expect(page.locator('#app')).toBeVisible({ timeout: 90_000 });
await waitForCourseRealmVisible(page); await waitForCourseRealmVisible(page);
await expect( const listError = page.getByText('请求失败,点击重新加载');
page.getByText('请求失败,点击重新加载') await expect(listError).toHaveCount(0, {
).not.toBeVisible({ timeout: 45_000 }); timeout: 45_000,
});
}); });
}); });