test(course-package): simplify teacher UI test with unionid login
Use new ?unionid=X&status=2 login support on teacher.moicen.com instead of the complex cookie-injection workaround (login on music-room → extract JWT → inject into teacher domain via document.cookie). Also seed course packages to both orgs (慧正书法 + 慧添翼) so the test works regardless of which org the role chooser selects first. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -216,95 +216,43 @@ test.describe('课包(course_package)', () => {
|
||||
test('教师端 UI:导航栏出现"课包"入口,页面加载种子数据', async ({
|
||||
page,
|
||||
}) => {
|
||||
// teacher.moicen.com 无 AuthCore 中间件,不支持 ?unionid= 登录;
|
||||
// 先在 music-room 域名登录获取 JWT,再注入 teacher 域名的 cookie+localStorage。
|
||||
await page.goto(`${teacherBase}/`, {
|
||||
waitUntil: 'domcontentloaded',
|
||||
timeout: 60_000,
|
||||
});
|
||||
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||
|
||||
// Step 1: 在 music-room 域登录以获取 JWT
|
||||
// 教师端现已支持 ?unionid=X&status=2 直接登录(UNIONID_LOGIN 开关),
|
||||
// 无需再绕 music-room 域提取 JWT 再注入 cookie。
|
||||
const q = new URLSearchParams({ unionid: moicenUnionid!, status: '2' });
|
||||
await page.goto(`/?${q.toString()}`, {
|
||||
await page.goto(`${teacherBase}/?${q.toString()}`, {
|
||||
waitUntil: 'domcontentloaded',
|
||||
timeout: 60_000,
|
||||
});
|
||||
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||
if (
|
||||
await page.getByText('请选择您的登录身份').isVisible().catch(() => false)
|
||||
) {
|
||||
await page.locator('.van-grid-item').first().click();
|
||||
}
|
||||
await expect(
|
||||
page.getByText(/请选择您的登录身份|欢迎回来|进入工作台/),
|
||||
).toBeVisible({ timeout: 120_000 });
|
||||
|
||||
if (
|
||||
await page.getByText('请返回微信小程序完成登录').isVisible().catch(() => false)
|
||||
) {
|
||||
test.skip(true, '当前 unionid 会话未处于可用登录态');
|
||||
// 路由守卫检测 ?unionid=X&status=2 后调用 login() → sudo() → read() → ensureOrgContext()
|
||||
// 完成后 redirect 到 /(query params 被剥离)。整个过程可能耗时 ~15s(多次 API 调用)。
|
||||
// 等待 URL 中 status=2 消失,说明登录 + redirect 已完成
|
||||
await page.waitForFunction(
|
||||
() => !window.location.search.includes('status=2'),
|
||||
{ timeout: 90_000 },
|
||||
);
|
||||
|
||||
// 首次登录可能会出现角色选择弹窗(Bootstrap modal)
|
||||
const roleChooser = page.locator('.modal-title').filter({ hasText: '选择角色' });
|
||||
if (await roleChooser.isVisible({ timeout: 10_000 }).catch(() => false)) {
|
||||
await page.locator('.modal .btn-primary').filter({ hasText: '确认' }).click();
|
||||
// 角色选择后会 full page reload(window.location.href = "/"),等待 reload 完成
|
||||
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||
}
|
||||
|
||||
// Step 2: 从 music-room 提取 auth 数据(JWT 在 localStorage,角色在 cookie)
|
||||
const jwt = await page.evaluate(() =>
|
||||
window.localStorage.getItem('Authorization'),
|
||||
);
|
||||
expect(jwt, '应有 JWT').toBeTruthy();
|
||||
// 导航栏渲染即表示已登录,检查"课包"入口
|
||||
const navLink = page.locator('nav a').filter({ hasText: '课包' });
|
||||
await expect(navLink).toBeVisible({ timeout: 30_000 });
|
||||
|
||||
const currentOrgId = await page.evaluate(() =>
|
||||
window.localStorage.getItem('CurrentOrgId'),
|
||||
);
|
||||
|
||||
const musicRoomCookies = await page.context().cookies();
|
||||
const findCookie = (name: string) =>
|
||||
musicRoomCookies.find((c) => c.name === name)?.value;
|
||||
const currentRole = findCookie('CurrentUserRole') || 'TEACHER';
|
||||
const currentUserName = findCookie('CurrentUserName') || 'e2e-test';
|
||||
|
||||
// Step 3: 跳转到 teacher 域名,注入 cookie + localStorage
|
||||
await page.goto(`${teacherBase}/`, {
|
||||
waitUntil: 'domcontentloaded',
|
||||
timeout: 60_000,
|
||||
});
|
||||
|
||||
// 使用 document.cookie 设置(addCookies 在某些 Chromium 版本上返回 Invalid cookie fields)
|
||||
await page.evaluate(
|
||||
({ token, role, userName }) => {
|
||||
const d = new Date();
|
||||
d.setFullYear(d.getFullYear() + 1);
|
||||
const attrs = `; path=/; domain=.moicen.com; expires=${d.toUTCString()}`;
|
||||
document.cookie = `HtyTeacherToken=${encodeURIComponent(token)}${attrs}`;
|
||||
document.cookie = `CurrentUserRole=${encodeURIComponent(role)}${attrs}`;
|
||||
document.cookie = `CurrentUserName=${encodeURIComponent(userName)}${attrs}`;
|
||||
},
|
||||
{ token: jwt!, role: currentRole, userName: currentUserName },
|
||||
);
|
||||
await page.evaluate(
|
||||
({ orgId }) => {
|
||||
if (orgId) window.localStorage.setItem('CurrentOrgId', orgId);
|
||||
},
|
||||
{ orgId: currentOrgId },
|
||||
);
|
||||
|
||||
// Step 4: 刷新,然后直接导航到课包页(路由守卫会读 cookie 放行)
|
||||
await page.reload({ waitUntil: 'domcontentloaded', timeout: 60_000 });
|
||||
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||
|
||||
// Step 5: 导航到 /course-packages,路由守卫应识别 HtyTeacherToken cookie 并放行
|
||||
// 导航到课包页并验证列表渲染
|
||||
await page.goto(`${teacherBase}/course-packages`, {
|
||||
waitUntil: 'domcontentloaded',
|
||||
timeout: 60_000,
|
||||
});
|
||||
await expect(page.locator('#app')).toBeVisible({ timeout: 60_000 });
|
||||
|
||||
// Step 6: 路由守卫异步 fetch 用户信息后,渲染导航栏与课包内容
|
||||
// 等待导航栏渲染(表明已登录),同时检查"课包"入口可见
|
||||
await page.waitForTimeout(3000);
|
||||
const navLink = page.locator('nav a').filter({ hasText: '课包' });
|
||||
await expect(navLink).toBeVisible({ timeout: 30_000 });
|
||||
|
||||
// Step 7: 页面应渲染课包列表(含预置种子数据)
|
||||
// 页面应渲染课包列表(含预置种子数据)
|
||||
await expect(page.getByText('钢琴一对一课程')).toBeVisible({ timeout: 30_000 });
|
||||
await expect(page.getByText('声乐基础训练')).toBeVisible({ timeout: 10_000 });
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user