Files

180 lines
6.1 KiB
TypeScript

import { expect, test } from "@playwright/test";
const diagnosticProgress = {
answered: 0,
total: 5,
effective_answered: 0,
min_questions: 3,
min_effective_answers: 3,
soft_cap: 5,
hard_cap: 8,
estimated_remaining_min: 3,
estimated_remaining_max: 5,
current_focus_concept_ids: [],
completion_confidence: 0,
placement_confidence: 0,
leading_start_concept_id: null,
leading_start_label: null,
runner_up_start_concept_id: null,
confidence_margin: 0,
current_focus_boundary_ids: [],
diagnostic_status: "active",
};
test("intro message keeps readable line width at the review viewport", async ({ page }) => {
await page.route("**/api/sessions", async (route) => {
await route.fulfill({
contentType: "application/json",
body: JSON.stringify({ session_id: "layout-session", stream_url: "/api/sessions/layout-session/events" }),
});
});
await page.route("**/api/sessions/layout-session/snapshot", async (route) => {
await route.fulfill({
contentType: "application/json",
body: JSON.stringify({
session_id: "layout-session",
last_event_id: null,
turns: [],
active_exercise: null,
active_project_step: null,
}),
});
});
await page.route("**/api/sessions/layout-session/events", async (route) => {
await route.fulfill({
contentType: "text/event-stream",
body: "",
});
});
await page.route("**/api/progress/me", async (route) => {
await route.fulfill({
contentType: "application/json",
body: JSON.stringify({
profile_summary: "",
current_level: "",
current_goal: null,
course_progress_percent: 0,
current_chapter_id: "intro",
current_chapter_title: "入门",
diagnostic: { ...diagnosticProgress, completed: false },
diagnostic_feedback: null,
curriculum: [],
mastery: [],
weak_concepts: [],
recommendations: [],
}),
});
});
await page.route("**/api/diagnostics/next", async (route) => {
await route.fulfill({
contentType: "application/json",
body: JSON.stringify({
diagnostic_id: "diagnostic-layout",
completed: false,
progress: diagnosticProgress,
}),
});
});
await page.setViewportSize({ width: 627, height: 694 });
await page.goto("/");
const introMessage = page.locator("section.conversation-column article.message.assistant").first();
await expect(introMessage.getByText("先完成初始测评来确定起点水平,然后查看学习起点和下一步建议。")).toBeVisible();
const metrics = await introMessage.locator(".markdown-content").evaluate((markdown) => {
const paragraph = markdown.querySelector("p");
const markdownRect = markdown.getBoundingClientRect();
const paragraphRect = paragraph?.getBoundingClientRect();
return {
markdownWidth: markdownRect.width,
paragraphWidth: paragraphRect?.width ?? 0,
};
});
expect(metrics.markdownWidth).toBeGreaterThan(300);
expect(metrics.paragraphWidth).toBeGreaterThan(metrics.markdownWidth * 0.75);
await expect(page.locator(".diagnostic-card.diagnostic-note")).toHaveCount(0);
await expect(page.getByText("测评进行中")).toHaveCount(0);
await expect(page.getByText("先确定学习起点", { exact: true })).toHaveCount(0);
});
test("active initial diagnostic does not show the diagnostic gate notice", async ({ page }) => {
await page.route("**/api/sessions", async (route) => {
await route.fulfill({
contentType: "application/json",
body: JSON.stringify({ session_id: "diagnostic-session", stream_url: "/api/sessions/diagnostic-session/events" }),
});
});
await page.route("**/api/sessions/diagnostic-session/snapshot", async (route) => {
await route.fulfill({
contentType: "application/json",
body: JSON.stringify({
session_id: "diagnostic-session",
last_event_id: null,
turns: [],
active_exercise: null,
active_project_step: null,
}),
});
});
await page.route("**/api/sessions/diagnostic-session/events", async (route) => {
await route.fulfill({
contentType: "text/event-stream",
body: "",
});
});
await page.route("**/api/progress/me", async (route) => {
await route.fulfill({
contentType: "application/json",
body: JSON.stringify({
profile_summary: "",
current_level: "",
current_goal: null,
course_progress_percent: 0,
current_chapter_id: "intro",
current_chapter_title: "入门",
diagnostic: { ...diagnosticProgress, completed: false },
diagnostic_feedback: null,
curriculum: [],
mastery: [],
weak_concepts: [],
recommendations: [],
}),
});
});
await page.route("**/api/diagnostics/next", async (route) => {
await route.fulfill({
contentType: "application/json",
body: JSON.stringify({
diagnostic_id: "diagnostic-active",
completed: false,
progress: diagnosticProgress,
question: {
id: "question-1",
concept_ids: ["dict"],
type: "multiple_choice",
prompt_md: "以下代码执行后,变量 `d` 的内容是什么?",
choices: [
{ id: "a", text: "{'name': 'Alice', 'age': 20}" },
{ id: "b", text: "{'name': 'Alice', 'age': 21, 'city': 'Beijing'}" },
{ id: "c", text: "{'name': 'Alice', 'city': 'Beijing'}" },
],
estimated_seconds: 45,
},
}),
});
});
await page.setViewportSize({ width: 1044, height: 694 });
await page.goto("/");
await expect(page.getByRole("heading", { name: "确定起点水平" })).toBeVisible();
await expect(page.getByRole("button", { name: "提交测评" })).toBeVisible();
await expect(page.locator(".diagnostic-card.diagnostic-note")).toHaveCount(0);
await expect(page.locator(".diagnostic-card.loading-card")).toHaveCount(0);
await expect(page.getByText("正在整理学习状态...")).toHaveCount(0);
await expect(page.getByText("测评进行中")).toHaveCount(0);
await expect(page.getByText("先确定学习起点", { exact: true })).toHaveCount(0);
});