PMFlow/frontend/src/features/personal-space/PersonalSpacePage.test.tsx

282 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import PersonalSpacePage from "./PersonalSpacePage";
import { spaceApi, type SpaceWorkbench } from "@/api/space";
import { renderWithProviders } from "@/test/renderWithProviders";
vi.mock("@/api/space", () => ({
spaceApi: {
getWorkbench: vi.fn(),
},
}));
vi.mock("@/features/pmflow-os/components/MobileBottomNav", () => ({
MobileBottomNav: () => <nav aria-label="mobile bottom nav" />,
}));
vi.mock("@/features/pmflow-os/components/AccountControls", () => ({
PMFlowAccountActions: () => <div data-testid="account-actions" />,
}));
const emptyWorkbench: SpaceWorkbench = {
projects: [],
pendingConfirmations: [],
aiProgress: [],
releaseAttention: [],
feedbackAttention: [],
savedIdeas: [],
drafts: [],
recentProjects: [],
warnings: ["暂存想法只读聚合尚未接入后端合同,当前不使用 mock 数据冒充真实内容。"],
generatedAt: "2026-04-26T08:00:00.000Z",
};
describe("PersonalSpacePage", () => {
it("renders the read-only Space workbench sections without demo saved ideas", async () => {
vi.mocked(spaceApi.getWorkbench).mockResolvedValue(emptyWorkbench);
renderWithProviders(<PersonalSpacePage />, ["/space"]);
expect(await screen.findAllByText("暂无可继续推进的项目")).not.toHaveLength(0);
expect(screen.getAllByText("个人工作面")).not.toHaveLength(0);
expect(screen.getAllByText("继续推进")).not.toHaveLength(0);
expect(screen.getAllByText("待我确认")).not.toHaveLength(0);
expect(screen.getAllByText("发布关注")).not.toHaveLength(0);
expect(screen.getAllByText("暂无发布验证记录")).not.toHaveLength(0);
expect(screen.getAllByText("发布后反馈关注")).not.toHaveLength(0);
expect(screen.getAllByText("暂无发布后反馈")).not.toHaveLength(0);
expect(screen.getAllByText("AI 正在推进")).not.toHaveLength(0);
expect(screen.getAllByText("暂存想法")).not.toHaveLength(0);
expect(screen.getAllByText("草案箱")).not.toHaveLength(0);
expect(screen.getAllByText("最近项目")).not.toHaveLength(0);
expect(screen.getAllByText("暂无暂存想法")).not.toHaveLength(0);
expect(screen.getByText("暂存想法只读聚合尚未接入后端合同,当前不使用 mock 数据冒充真实内容。")).toBeInTheDocument();
expect(screen.queryByText("AI 周报助手")).not.toBeInTheDocument();
});
it("keeps workbench actions as navigation-only links into the main flows", async () => {
vi.mocked(spaceApi.getWorkbench).mockResolvedValue({
...emptyWorkbench,
projects: [
{
id: "17",
title: "真实项目",
summary: "真实项目摘要",
status: "进行中",
stage: "开发",
progress: 62,
pendingCount: 1,
activeTaskCount: 2,
riskLabel: "中",
nextAction: "继续推进核心任务",
updatedAt: "2026-04-26T08:00:00.000Z",
href: "/pmflow-os?projectId=17",
},
],
pendingConfirmations: [
{
id: "change-91",
projectId: "17",
projectTitle: "真实项目",
title: "确认需求变更",
summary: "等待在主流程确认变更。",
source: "changeset",
stage: "需求",
riskLevel: "medium",
createdAt: "2026-04-26T08:00:00.000Z",
href: "/change-review?projectId=17&changeSetId=91",
},
],
aiProgress: [
{
id: "execution-17",
projectId: "17",
projectTitle: "真实项目",
title: "AI 正在推进执行链路",
summary: "正在聚合执行进度与回写状态。",
status: "coding",
progress: 52,
updatedAt: "2026-04-26T08:00:00.000Z",
href: "/execution-bridge?projectId=17",
},
],
releaseAttention: [
{
id: "release-attention-17",
projectId: "17",
projectTitle: "真实项目",
source: "release_validation",
sourceLabel: "发布验证记录",
title: "发布验证阻塞",
summary: "测试失败,PR 未合并,不能发布。",
gateStatus: "blocked",
severity: "high",
reasons: ["测试失败: typecheck 未通过", "PR: 未合并"],
evidenceLabels: ["发布验证", "检查阻塞", "1/2 检查项通过"],
updatedAt: "2026-04-26T08:00:00.000Z",
href: "/release-growth?projectId=17",
},
{
id: "release-validation-18",
projectId: "18",
projectTitle: "待确认项目",
source: "release_validation",
sourceLabel: "发布验证记录",
title: "发布验证待确认",
summary: "发布验证已通过,需要人工确认。",
gateStatus: "needs_confirmation",
severity: "medium",
reasons: [],
evidenceLabels: ["发布验证", "验证通过"],
updatedAt: "2026-04-26T08:00:00.000Z",
href: "/release-growth?projectId=18",
},
{
id: "release-gate-19",
projectId: "19",
projectTitle: "候选项目",
source: "release_gate",
sourceLabel: "发布门禁",
title: "发布候选",
summary: "执行证据已进入发布判断。",
gateStatus: "ready",
severity: "low",
reasons: [],
evidenceLabels: ["测试通过", "PR"],
updatedAt: "2026-04-26T08:00:00.000Z",
href: "/release-growth?projectId=19",
},
],
feedbackAttention: [
{
id: "feedback-signal-17-feedback-1",
projectId: "17",
projectTitle: "真实项目",
source: "feedback",
sourceLabel: "用户反馈",
title: "新反馈信号",
summary: "用户反馈集中在 onboarding 卡顿。",
value: "12",
severity: "medium",
updatedAt: "2026-04-26T08:00:00.000Z",
href: "/release-growth?projectId=17",
},
{
id: "feedback-signal-17-revenue-1",
projectId: "17",
projectTitle: "真实项目",
source: "revenue",
sourceLabel: "收入信号",
title: "收入信号更新",
summary: "付费转化新增。",
value: "USD 1200",
severity: "low",
updatedAt: "2026-04-26T08:00:00.000Z",
href: "/release-growth?projectId=17",
},
{
id: "feedback-signal-17-compliance-1",
projectId: "17",
projectTitle: "真实项目",
source: "compliance",
sourceLabel: "合规检查",
title: "合规阻塞关注",
summary: "隐私文案未通过。",
value: "blocked",
severity: "high",
updatedAt: "2026-04-26T08:00:00.000Z",
href: "/release-growth?projectId=17",
},
{
id: "feedback-iteration-17-change-92",
projectId: "17",
projectTitle: "真实项目",
source: "iteration",
sourceLabel: "下一轮建议",
title: "下一轮建议待处理",
summary: "基于发布后反馈生成下一轮优化建议。",
value: null,
severity: "medium",
updatedAt: "2026-04-26T08:00:00.000Z",
href: "/change-review?projectId=17&changeSetId=92",
},
],
drafts: [
{
id: "17-需求-draft-1",
projectId: "17",
projectTitle: "真实项目",
title: "待确认草案",
summary: "待确认草案摘要",
objectType: "需求",
status: "draft",
updatedAt: "2026-04-26T08:00:00.000Z",
href: "/pmflow-os?projectId=17",
},
],
recentProjects: [
{
id: "17",
title: "真实项目",
summary: "真实项目摘要",
status: "进行中",
stage: "开发",
progress: 62,
pendingCount: 1,
activeTaskCount: 2,
riskLabel: "中",
nextAction: "继续推进核心任务",
updatedAt: "2026-04-26T08:00:00.000Z",
href: "/pmflow-os?projectId=17",
},
],
});
renderWithProviders(<PersonalSpacePage />, ["/space"]);
expect(await screen.findByRole("link", { name: /进入主流程/ })).toHaveAttribute(
"href",
"/pmflow-os?projectId=17"
);
expect(screen.getAllByRole("link", { name: /确认需求变更/ })[0]).toHaveAttribute(
"href",
"/change-review?projectId=17&changeSetId=91"
);
expect(screen.getAllByRole("link", { name: /AI 正在推进执行链路/ })[0]).toHaveAttribute(
"href",
"/execution-bridge?projectId=17"
);
expect(screen.getAllByRole("link", { name: /发布验证阻塞/ })[0]).toHaveAttribute(
"href",
"/release-growth?projectId=17"
);
expect(screen.getAllByRole("link", { name: /发布验证待确认/ })[0]).toHaveAttribute(
"href",
"/release-growth?projectId=18"
);
expect(screen.getAllByRole("link", { name: /发布候选/ })[0]).toHaveAttribute(
"href",
"/release-growth?projectId=19"
);
expect(screen.getAllByRole("link", { name: /新反馈信号/ })[0]).toHaveAttribute(
"href",
"/release-growth?projectId=17"
);
expect(screen.getAllByRole("link", { name: /收入信号更新/ })[0]).toHaveAttribute(
"href",
"/release-growth?projectId=17"
);
expect(screen.getAllByRole("link", { name: /合规阻塞关注/ })[0]).toHaveAttribute(
"href",
"/release-growth?projectId=17"
);
expect(screen.getAllByRole("link", { name: /下一轮建议待处理/ })[0]).toHaveAttribute(
"href",
"/change-review?projectId=17&changeSetId=92"
);
expect(screen.getAllByText("测试失败: typecheck 未通过")).not.toHaveLength(0);
expect(screen.queryByRole("button", { name: /创建发布验证|运行发布验证|重新验证/ })).not.toBeInTheDocument();
expect(screen.queryByRole("button", { name: /创建反馈|写入反馈|记录收入|运行合规/ })).not.toBeInTheDocument();
});
});