test(course-package): verify against seeded data from moicen DB
Add pre-seeded course packages for 阿难 on moicen DB: 钢琴一对一课程, 声乐基础训练, 乐理知识速成 (INACTIVE). Update pagination tests to assert specific names, ACTIVE filtering, sort order, and INACTIVE exclusion. Extract shared loginAndGetJwt helper to reduce duplication. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -33,28 +33,21 @@ function extractRoleKeys(payload: Record<string, unknown> | null): string[] {
|
||||
.filter((k): k is string => typeof k === 'string' && k.length > 0);
|
||||
}
|
||||
|
||||
test.describe('课包(course_package)', () => {
|
||||
test.describe.configure({ timeout: 180_000 });
|
||||
|
||||
test.skip(!moicenUnionid, '需要 MOICEN_E2E_UNIONID(Secret 或 .env.e2e)');
|
||||
|
||||
test('权限校验:当前账号 JWT 应包含 TEACHER 或 SUPERVISOR 角色', async ({
|
||||
page,
|
||||
}) => {
|
||||
/** 共用的登录 + JWT 提取逻辑 */
|
||||
async function loginAndGetJwt(page: any): Promise<string> {
|
||||
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 });
|
||||
|
||||
if (
|
||||
await page.getByText('请选择您的登录身份').isVisible().catch(() => false)
|
||||
) {
|
||||
await page.locator('.van-grid-item').first().click();
|
||||
}
|
||||
await expect(
|
||||
page.getByText(/请选择您的登录身份|欢迎回来|进入工作台/)
|
||||
page.getByText(/请选择您的登录身份|欢迎回来|进入工作台/),
|
||||
).toBeVisible({ timeout: 120_000 });
|
||||
|
||||
if (
|
||||
@@ -64,11 +57,23 @@ test.describe('课包(course_package)', () => {
|
||||
}
|
||||
|
||||
const authToken = await page.evaluate(() =>
|
||||
window.localStorage.getItem('Authorization')
|
||||
window.localStorage.getItem('Authorization'),
|
||||
);
|
||||
expect(authToken, '登录后应有 JWT').toBeTruthy();
|
||||
return authToken!;
|
||||
}
|
||||
|
||||
const payload = decodeJwtPayload(authToken!);
|
||||
test.describe('课包(course_package)', () => {
|
||||
test.describe.configure({ timeout: 180_000 });
|
||||
|
||||
test.skip(!moicenUnionid, '需要 MOICEN_E2E_UNIONID(Secret 或 .env.e2e)');
|
||||
|
||||
test('权限校验:当前账号 JWT 应包含 TEACHER 或 SUPERVISOR 角色', async ({
|
||||
page,
|
||||
}) => {
|
||||
const authToken = await loginAndGetJwt(page);
|
||||
|
||||
const payload = decodeJwtPayload(authToken);
|
||||
expect(payload, 'JWT 应可解码').not.toBeNull();
|
||||
|
||||
const roles = extractRoleKeys(payload);
|
||||
@@ -85,36 +90,11 @@ test.describe('课包(course_package)', () => {
|
||||
page,
|
||||
request,
|
||||
}) => {
|
||||
// ---- 登录获取 JWT ----
|
||||
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 });
|
||||
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 会话未处于可用登录态');
|
||||
}
|
||||
|
||||
const authToken = await page.evaluate(() =>
|
||||
window.localStorage.getItem('Authorization'),
|
||||
);
|
||||
expect(authToken, '应有 Authorization JWT').toBeTruthy();
|
||||
const authToken = await loginAndGetJwt(page);
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
Authorization: authToken!,
|
||||
HtySudoerToken: authToken!,
|
||||
Authorization: authToken,
|
||||
HtySudoerToken: authToken,
|
||||
HtyHost: new URL(kcBase).hostname,
|
||||
};
|
||||
|
||||
@@ -178,64 +158,55 @@ test.describe('课包(course_package)', () => {
|
||||
expect(deleteBody.r, `DELETE 业务失败: ${JSON.stringify(deleteBody)}`).toBe(true);
|
||||
});
|
||||
|
||||
test('分页查询:my-packages / org-packages 接口正常', async ({
|
||||
test('分页查询:my-packages / org-packages 返回预置种子数据', async ({
|
||||
page,
|
||||
request,
|
||||
}) => {
|
||||
// ---- 登录获取 JWT ----
|
||||
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 });
|
||||
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 会话未处于可用登录态');
|
||||
}
|
||||
|
||||
const authToken = await page.evaluate(() =>
|
||||
window.localStorage.getItem('Authorization'),
|
||||
);
|
||||
expect(authToken).toBeTruthy();
|
||||
const authToken = await loginAndGetJwt(page);
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
Authorization: authToken!,
|
||||
HtySudoerToken: authToken!,
|
||||
Authorization: authToken,
|
||||
HtySudoerToken: authToken,
|
||||
HtyHost: new URL(kcBase).hostname,
|
||||
};
|
||||
|
||||
// ---- my-packages(当前教师创建的课包)----
|
||||
// ---- my-packages(当前教师创建的课包,含 INACTIVE)----
|
||||
const myRes = await request.get(
|
||||
`${kcBase}/api/v1/clazz/course-package/my-packages?page=1&page_size=5`,
|
||||
`${kcBase}/api/v1/clazz/course-package/my-packages?page=1&page_size=10`,
|
||||
{ headers },
|
||||
);
|
||||
expect(myRes.ok(), `my-packages HTTP ${myRes.status()}`).toBeTruthy();
|
||||
const myBody = await myRes.json();
|
||||
expect(myBody.r, `my-packages 业务失败: ${JSON.stringify(myBody)}`).toBe(true);
|
||||
expect(Array.isArray(myBody.d?.[0])).toBe(true);
|
||||
const myList: any[] = myBody.d?.[0] ?? [];
|
||||
expect(myList.length).toBeGreaterThanOrEqual(3);
|
||||
// 应包含预置种子:钢琴一对一课程、声乐基础训练、乐理知识速成
|
||||
const myNames = myList.map((p: any) => p.package_name);
|
||||
expect(myNames).toContain('钢琴一对一课程');
|
||||
expect(myNames).toContain('声乐基础训练');
|
||||
expect(myNames).toContain('乐理知识速成');
|
||||
expect(typeof myBody.d?.[1] === 'number').toBe(true); // total pages
|
||||
expect(typeof myBody.d?.[2] === 'number').toBe(true); // total count
|
||||
|
||||
// ---- org-packages(机构下所有活跃课包)----
|
||||
// ---- org-packages(机构下活跃课包,仅 ACTIVE,按 sort_order 升序)----
|
||||
const orgRes = await request.get(
|
||||
`${kcBase}/api/v1/clazz/course-package/org-packages?page=1&page_size=5`,
|
||||
`${kcBase}/api/v1/clazz/course-package/org-packages?page=1&page_size=10`,
|
||||
{ headers },
|
||||
);
|
||||
expect(orgRes.ok(), `org-packages HTTP ${orgRes.status()}`).toBeTruthy();
|
||||
const orgBody = await orgRes.json();
|
||||
expect(orgBody.r, `org-packages 业务失败: ${JSON.stringify(orgBody)}`).toBe(true);
|
||||
expect(Array.isArray(orgBody.d?.[0])).toBe(true);
|
||||
const orgList: any[] = orgBody.d?.[0] ?? [];
|
||||
// 应包含 2 个 ACTIVE 种子,不包含 INACTIVE 的「乐理知识速成」
|
||||
expect(orgList.length).toBeGreaterThanOrEqual(2);
|
||||
const orgNames = orgList.map((p: any) => p.package_name);
|
||||
expect(orgNames).toContain('钢琴一对一课程');
|
||||
expect(orgNames).toContain('声乐基础训练');
|
||||
expect(orgNames).not.toContain('乐理知识速成');
|
||||
// 按 sort_order 升序排列,钢琴一对一(sort=1)在前
|
||||
const pianoIdx = orgNames.indexOf('钢琴一对一课程');
|
||||
const vocalIdx = orgNames.indexOf('声乐基础训练');
|
||||
expect(pianoIdx).toBeLessThan(vocalIdx);
|
||||
expect(typeof orgBody.d?.[1] === 'number').toBe(true);
|
||||
expect(typeof orgBody.d?.[2] === 'number').toBe(true);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user