Files
yx-react-template/tests/e2e/course-flow.spec.ts
T
2026-08-27 10:35:17 +08:00

175 lines
5.9 KiB
TypeScript

import { expect, type Locator, type Page, test } from "@playwright/test";
async function dragWithPointer(
page: Page,
source: Locator,
target: Locator,
): Promise<void> {
const sourceBox = await source.boundingBox();
const targetBox = await target.boundingBox();
if (!sourceBox || !targetBox) {
throw new Error("Drag source or target is not visible");
}
const sourcePosition = {
x: sourceBox.x + sourceBox.width / 2,
y: sourceBox.y + sourceBox.height / 2,
};
const targetPosition = {
x: targetBox.x + targetBox.width / 2,
y: targetBox.y + targetBox.height / 2,
};
await page.mouse.move(sourcePosition.x, sourcePosition.y);
await page.mouse.down();
await page.mouse.move(sourcePosition.x + 10, sourcePosition.y, { steps: 5 });
await page.waitForTimeout(150);
await page.mouse.move(targetPosition.x, targetPosition.y, { steps: 20 });
await page.waitForTimeout(150);
await page.mouse.up();
}
function getResource(page: Page, title: string): Locator {
return page.getByRole("button", { name: new RegExp(title) });
}
function getCategory(page: Page, title: string): Locator {
return page.getByRole("heading", { name: title, exact: true }).locator("..");
}
test.describe("CourseDemo connected flow", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/#/course-demo");
await page.waitForLoadState("networkidle");
});
test("renders header and progress", async ({ page }) => {
await expect(page.locator("text=学生资助政策 · 互动学习")).toBeVisible();
await expect(page.locator("text=建立你的课程资源地图")).toBeVisible();
await expect(page.locator('[data-guide="course-progress"]')).toBeVisible();
await expect(page.locator("text=本节进度")).toBeVisible();
});
test("starts guide dialog and navigates steps", async ({ page }) => {
await page.click("text=进入课程导入");
await page.waitForTimeout(500);
// First step should appear
await expect(page.locator("text=欢迎进入学生资助政策微课")).toBeVisible();
await expect(page.locator("text=1 / 4")).toBeVisible();
// Click next
await page.click("button:has-text('了解任务')");
await page.waitForTimeout(300);
await expect(page.locator("text=选择你的学习方式")).toBeVisible();
await expect(page.locator("text=2 / 4")).toBeVisible();
// Choose direct path
await page.click("button:has-text('直接开始分类')");
await page.waitForTimeout(300);
await expect(page.locator("text=准备开始")).toBeVisible();
await expect(page.locator("text=4 / 4")).toBeVisible();
// Finish
await page.click("button:has-text('开始挑战')");
await page.waitForTimeout(300);
// Dialog should close
await expect(
page.locator("text=欢迎进入学生资助政策微课"),
).not.toBeVisible();
});
test("starts spotlight guide and highlights elements", async ({ page }) => {
await page.click("text=查看操作引导");
await page.waitForTimeout(500);
// First spotlight step
await expect(page.locator("text=先阅读资源卡片")).toBeVisible();
await page.waitForTimeout(300);
// Next step
await page.click("button:has-text('下一步')");
await page.waitForTimeout(500);
await expect(page.locator("text=放入对应学习阶段")).toBeVisible();
// Next step
await page.click("button:has-text('下一步')");
await page.waitForTimeout(500);
await expect(page.locator("text=自动记录学习进度")).toBeVisible();
// Finish
await page.click("button:has-text('开始分类')");
await page.waitForTimeout(300);
await expect(page.locator("text=先阅读资源卡片")).not.toBeVisible();
});
test("drag and drop resource classification", async ({ page }) => {
const policyResource = getResource(page, "资助政策微课");
const policyZone = getCategory(page, "政策学习");
await expect(policyResource).toBeVisible();
await expect(policyZone).toBeVisible();
await dragWithPointer(page, policyResource, policyZone);
await expect(page.getByText("分类正确:资助政策微课")).toBeVisible();
await expect(page.getByText("已完成 1/6")).toBeVisible();
await expect(policyResource).not.toBeVisible();
});
test("wrong category shows error toast", async ({ page }) => {
const policyResource = getResource(page, "资助政策微课");
const wrongZone = getCategory(page, "互动实践");
await expect(policyResource).toBeVisible();
await expect(wrongZone).toBeVisible();
await dragWithPointer(page, policyResource, wrongZone);
await expect(
page.getByText("“资助政策微课”不属于这个分类,再想一想。"),
).toBeVisible();
await expect(page.getByText("已完成 0/6")).toBeVisible();
await expect(policyResource).toBeVisible();
});
test("completion overlay appears after all resources placed", async ({
page,
}) => {
const placements = [
["资助政策微课", "政策学习"],
["申请流程图", "政策学习"],
["诚信申请案例", "互动实践"],
["材料自查清单", "互动实践"],
["常见问题答疑", "学习支持"],
["校园咨询渠道", "学习支持"],
] as const;
for (const [resourceTitle, categoryTitle] of placements) {
await dragWithPointer(
page,
getResource(page, resourceTitle),
getCategory(page, categoryTitle),
);
}
await expect(page.getByText("资源地图已建立")).toBeVisible();
await expect(page.getByText("已完成 6/6")).toBeVisible();
await expect(page.getByText("100%")).toBeVisible();
});
test("persists progress with session fallback", async ({ page }) => {
await dragWithPointer(
page,
getResource(page, "资助政策微课"),
getCategory(page, "政策学习"),
);
await expect(page.getByText("已完成 1/6")).toBeVisible();
await page.reload();
await expect(page.getByText("进度已恢复")).toBeVisible();
await expect(page.getByText("已完成 1/6")).toBeVisible();
await expect(getResource(page, "资助政策微课")).not.toBeVisible();
});
});